TS06 TypeScript高级用法
TypeScript中的一些高级技巧。
使用泛型+type定义类型函数
使用type+泛型,可以定义类型函数:
1 | type foo<T> = T; |
可以对泛型入参进行约束、设置默认值
1 | // 对入参进行约束 |
条件判断
TypeScript中使用extends进行类型判断,与三元运算符很相似:
1 | T extends U ? X : Y; |
如果T的类型能够extends U,结果返回X,否则返回Y。
结合上面的类型函数,可以进行扩展:
1 | type num = 1; |
遍历联合类型
使用in关键在来遍历type的联合类型
联合类型就是使用
|来定义的类型的合集
1 | type Key = 'vue' | 'react'; |
如果联合类型不是我们显式的定义出来的,那么想要动态的推导出联合类型的类型,需要使用keyof方法
1 | interface Person { |
对联合类型进行map操作
可以使用extends+泛型,实现将一组联合类型批量映射为另一种类型:
1 | type Foo = 'a' | 'b'; |
全局作用域
使用declare关键字来声明全局作用域:
1 | declare module '*.png'; |
要注意,如果模块使用了export关键字导出了内容,上述方式可能会失效,需要显式的声明到全局:
1 | declare global { |
注意,上述方式之恩能够用在模块声明内,也就是说代码中必须包含export,否则就会报错:
1 | TS2669: Augmentations for the global scope can only be directly nested in external modules or ambient module declarations. |
模块作用域
模块作用域的触发条件之一就是使用export关键字导出内容,在其他模块获取时需要import导入
never类型的作用
never类型代表空集,常用语校验“类型收窄”是否符合预期,常被用来做“类型收底”。
例如,有一个联合类型时:
1 | interface Foo { |
在switch判断type,TS是可以收窄类型的(discriminated union):
1 | funcfunction handleValue(val: All) { |
在default里面把收窄的never的val赋给了显示声明为never的变量。如果有一天type类型被修改了:
1 | type All = Foo | Bar | Baz |
如果没有在handleValue添加针对Baz的处理逻辑,这时候在default的分支中就会编译错误。所以通过这个办法可以确保switch总是穷尽了所有All的可能性
用never进行类型过滤联合类型
当never参与运算时T | never 的结果是T,根据这个规则就可以过滤联合类型中不符合期望的类型,TS内置的Exclude泛型操作符就是根据这个原理实现的:
1 | /** |
自定义类型守卫
类型守卫(Type Guard)的目的就是为了对类型进行分流,将联合类型分发到不同管道。可以出发类型守卫的常见方式有:typeof、instancof、in、==、===、!=、!==等
1 | function foo(x: A | B) { |
当以上的方式不满足需求时,可以通过is关键字自定义类型守卫:
1 | function isA(x): x is number { |