You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
typeParseInt=(n: string)=>number// 如果是类型 T 是函数,则 R 会捕获其返回值类型并返回 R,否则返回 anytypeReturnType<Textends(...args: any)=>any>=Textends(...args: any)=> infer R ? R : anytypeR=ReturnType<ParseInt>// numbertypeGetType<T>=Textends(infer E)[] ? E : nevertypeE=GetType<['a',100]>
typea=stringtypeb=numbertypec=nevertyped=a|b|c// type d = string | numbertypeExclude<T,U>=TextendsU ? never : T;typeT=Exclude<string|number,string>// number
编写 TypeScript(后面简称TS)应用是一个与类型斗争的过程,你需要使用 TS 提供的类型工具通过不同的组合来精确描述你的目标。描述越精确,类型约束和提示越准确,潜在错误越少。反之,描述越模糊(如
any
一把唆),TS 能提供的类型辅助就越少,潜在的错误也就越多。如何描写精确的类型描述需要掌握 TS 的基础概念,同时掌握常见技巧和类型工具,前者可以阅读官网的 TypeScript 手册 学习,后者可以通过本文学习一二,后续进阶学习就靠多实践多总结了。常用技巧
这节主要介绍一些基础的类型工具,这是所有高级类型的基石。
typeof T
- 获取 JS 值的类型typeof
可以获取 JS 变量的类型,它是 JS 值空间向 TS 类型空间转换的桥梁,有了它我们可以从已有的变量中抽取类型进行进一步处理。keyof T
- 获取类型的键keyof
可获取目标类型的键,返回的是string | number | symbol
的子类型。T[K]
- 索引类型,获取类型的值动态获取目标类型属性的类型,类似 JS 中对象取值操作,不过这里取到的是值的类型。
[P in keyof T]: T[P]
- 类型映射,转换类型基于旧类型创建新类型,在新类型构造过程中,我们可以对旧类型的属性名、属性值进行重写,从而实现类型转换。其中
in
操作符表示遍历目标类型的 key。T extends U ? X : Y
- 条件类型extends
除了用在继承类时会使用,还可以用于判断一个类型是否是另一个类型的父类型,并根据判断结果执行不同的类型分支,其使得 TS 类型具备了一定的编程能力。extends
条件判断规则如下:如果T
可以赋值给U
返回X
,否则Y
,如果 TS 无法确定T
是否可以赋值给U
,则返回X | Y
。infer T
- 类型推断在
extends
条件类型的子句中,可以使用infer T
来捕获指定位置的类型(该类型由 TS 编译器推断),在infer
后面的子句中可以使用捕获的类型变量。配合extends
条件类型,截取符合条件的目标的某部分类型。never
never
与类型T
(T
是除unknown
外的其他任意类型)union 后结果是类型T
,利用never
的这个特点可以实现类型消除,例如将某个类型先转换成never
,然后再与其他类型 union。类型工具
TS 内置了一些常用的类型转换工具,熟练掌握这些工具类型不仅可以简化类型定义,而且可以基于此构建更复杂的类型转换。
下面是 TS 内置的所有类型工具,我加了下注释和示例方便理解,你可以先只看示例,测试下能否自行写出对应的类型实现(Playground)。
除了 TS 内置的类型工具外,还有一些第三方开发的类型工具,提供了更多类型转换工具,例如 ts-toolbelt —— TS 版"lodash"库。
下面是从 ts-toolbelt 挑选的部分示例,更多工具类型请查看它的官网。
案例解析
掌握基础概念后,可能依然无法写出精确的类型描述,因为这些概念仅仅停留在单个概念的使用,需要进一步实践练习,才可能融会贯通。下面搜集了一些 TS 的类型转换案例(题目),可以从中学习一些解题思路和代码实现。
No.1
问题
假定对象的所有值都是数组类型,例如:
要求获取上述对象值中的数组元素的类型,例如:
解题思路
首先拿到对象的值类型,然后通过数组下标获取数组元素的类型。
参考代码
扩展
如果对象的值不都是数组类型呢?
例如下面这样
解题思路:首先依然是拿到对象的值类型,然后过滤出数组类型,最后取数组的元素类型
No.2
问题
假设有一个
EffectModule
类,它包含成员变量和成员方法,代码如下:现在有一个叫
connect
的函数,它接受EffectModule
实例,将它变成另一个对象,这个对象上只有EffectModule
的同名方法,即经过
connect
函数后,方法的类型签名变成了:要求实现下面的
Connect
函数类型,将any
替换成题目的解答后,让编译器可以顺利编译通过,并且返回的类型与Connected
相同。解题思路
EffectModule
实例的成员方法T extends U
判断方法签名a. 如果方法签名符合条件,使用
infer
捕获 Promise 和 Action 中的泛型参数,并返回正确的方法类型签名b. 否则,返回方法原始的类型签名
参考代码
上面的
TransformFunctions
的实现也可以简单点写,例如将返回值类型Promise<Action<infer R>>
改成Promise<infer R>
,却别在于前者判断时更加精准。前者约束返回值必须是 Promise + Action 类型,而后者只约束返回值是 Promise 类型。案例部分未完待续。。。
参考
The text was updated successfully, but these errors were encountered: