引文
在刚接触TypeScript的时候,应用最多的就是type和interface这两个关键字,用来申明类型,其实这样也根本满足日常需要。然而如果须要设计一些高级类型的话,那么仅仅用原来所把握的TypeScript常识是无奈满足需要的。
设计高级类型的话波及到类型编程的知识点,而类型编程中有两个关键字十分重要,别离是extends和infer。
extends用来束缚入参的类型以及进行条件判断,infer用来申明部分的类型变量。
extends
条件判断
咱们举个简略的例子来阐明
type isOne<T extends number> = T extends 1 ? true : false
咱们独自看T extends 1 ? true : false
这部分,这里和JavaScript
中的三元表达式并无二致,然而有些同学不分明其中extends示意的是什么含意。
T extends 1 ? true : false示意的含意其实就是传入的T类型是否可能赋值给字面量1这个类型,如果能够的话,就返回true,否则返回false
束缚参数类型
持续应用下面的例子,咱们独自看T extends number
,这里extends的意思就是限度传入的T类型必须是number类型,否则报错。
为什么须要有这个限度?
因为咱们是要判断类型T是否可能赋值给字面量类型1,然而如果传入的参数都不是number类型,那么就没必要做后续的条件判断了。
束缚infer推导的局部变量类型
type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest] ? `${FirstChar}` : never;type Res = GetFirst<['1', '2', '3']>;
来看看报错信息,咱们传入的参数类型限度为sting类型的数组,然而infer推导进去的类型实际上是unknown类型,所以导致类型不匹配。
解决办法有三种:
对FirstChar应用extends先做过滤
type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest]? FirstChar extends string ? `${FirstChar}` : never: never;
FirstChar和string进行穿插运算
type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest]? `${FirstChar & string}`: never;
应用infer extends做类型转换
type GetFirst<T extends string[]> = T extends [infer FirstChar extends string,...infer Rest]? `${FirstChar}`: never;
infer extends
是在ts 4.7版本反对,低于这个版本无奈应用。类型转换
type StrToNum<T extends string> = T extends `${infer Num extends number}` ? Num : Ttype Res = StrToNum<"1">// ts 4.7时,返回的后果是type Res = number// ts 4.8及以上, 返回的后果是type Res = 1
infer
还是拿例子来进行解说,上面的例子是要提取Promise包裹的类型。
type PromiseValue<T extends Promise<unknown>> = T extends Promise<infer Value> ? Value : nevertype Res = PromiseValue<Promise<string>> // string
画个简略的图来形容下如何提取变量类型。
留神:infer申明的局部变量,只能在条件语句为true的分支外面应用。
间接报错示意找不到通过infer申明的局部变量。
组合应用
ReturnType
内置工具类型RetureType用于获取函数的返回值类型。
type MyReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;type Res = MyReturnType<() => string> // type Res = string
Parameters
内置工具类型Parameters用于获取函数的参数类型。
type MyParameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;type Res = MyParameters<(a: string, b: number) => void> // type Res = [a: string, b: number]