在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
记录一些自己在ts上费过时间的地方。 (先吐个槽:stackoverflow是真的啥都有,百度是真的没法用) 坑as断言的兼容性误解,如"a" as "b"这种代码是不会报错的。 interface和type的不一致行为(初遇还以为自己写错类型,一脸懵逼的): type Type = { key: "value" } interface Interface { key: "value" } type 似乎没差别都是true = Type extends Interface ? Type extends Interface ? true : false : false type 坑点 = { [key: string]: 坑点 } | string type 测试<T> = T extends 坑点 ? true : false type 这个是true = 测试<Type> type 这个是false = 测试<Interface> github上官方有说明,是故意留这么个坑的。说是因为interface可扩展(同名自动合并),所以不便检测。 用泛型实现函数重载的效果时,在函数的实现中,会因泛型不具备具体约束,导致经常需要使用as强制断言。 //差不多这意思,下面的代码懒得实际测了🙃 //fns是个函数索引表,TFns是索引表的const类型 function 重载失败<T extends keyof TFns>(fn:T, params: Parameters<fns[T]>){ fns[fn](...params)//在实现中联合类型不会缩小,所以会报错 //错误应该像是 不能将方法1的参数传给方法2 这种 } //但外部使用时,符合类型的语义也没啥事 扩展运算符并不符合直观感受: 其实这里有解决办法,但是写出来的类型简直没法看(几十行,包含大量extends充当类型的if判断),就不贴了 下面贴代码: //需要的类型:[...number[], "middle-element", ...boolean[]] //上面的写法是无效的,只是示意下面的类型代码是干什么用的(实现上面示意的类型约束) type Elem = number | boolean | "middle-element"; type Last<T extends any[]> = T extends [infer _] ? never : T extends [...infer _, infer Tl] ? Tl : never type HandleEmpty<T extends any[], Data> = T['length'] extends 0 ? never : Data type Validation<Params extends any[], Cache extends Elem[] = []> = Params extends [] ? Cache['length'] extends 0 ? never : Cache : Params extends [infer Fst, ...infer Rest] ? Cache extends [] ? Fst extends number ? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>> : never : Fst extends number ? Last<Cache> extends number ? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>> : never : Fst extends "middle-element" ? Last<Cache> extends number ? HandleEmpty<Rest, Validation<Rest, [...Cache, Fst]>> : never : "middle-element" extends Cache[number] ? Fst extends boolean ? Validation<Rest, [...Cache, Fst]> : never : never : never type IsNever<T> = [T] extends [never] ? true : false; function check< Params extends Elem[], IsValid extends Validation<Params> >(...arr: IsNever<IsValid> extends true ? [never] : [...Params]) { return arr } const 正常 = check(1, 'middle-element', false) const 报错 = check(false, "middle-element", 2) 进阶操作对象名重映射: //{ "new-a":any; "new-b":any } type 重映射 = { [K in "a" | "b" as `new-${K}`]: any } 联合类型的拆分:用infer关键字可以实现对联合类型的拆分。 //"a1"|"b2" type 拆分成功<_Keys = keyof { a: 1, b: 2 }> = _Keys extends infer K ? `${Extract<K, string>}${{ a: 1, b: 2 }[Extract<K, _Keys>]}` : never //注意:(截止ts4.4.4)直接`keyof Obj extends infer K`无法分割联合类型,原因不明(懒得查😁)。 //结果是"a1"|"a2"|"b1"|"b2" type 拆分失败 = keyof { a: 1, b: 2 } extends infer K ? `${Extract<K, string>}${{ a: 1, b: 2 }[Extract<K, "a" | "b">]}` : never 元组类型:
递归类型:用...infer More可以实现对数组类型的递归。 type 转换器<T> = T extends string ? "str" : null //进去是个[string,number,string],出来就会是["str",null,"str"] type 递归< 输入源 extends any[], 内部的类型缓存 extends any[] = [] > = 输入源 extends [any, ...infer 剩余元素] ? 递归<剩余元素, [...内部的类型缓存, 转换器<输入源[0]>]> : 输入源 零碎
新手建议去官网翻文档。 入了ts坑后,可以没事关注下版本更新带来的新特性(玩法)。 总结到此这篇关于在TypeScript上费过时间的地方总结的文章就介绍到这了,更多相关ts费时间的地方内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论