TS数据类型(2):类型模式匹配技术——条件类型+infer
Author:zhoulujun Date:
类型模式匹配技术
TypeScript 提供的类型模式匹配技术 —— 条件类型 + infer。
条件类型允许我们检测两种类型之间的关系,通过条件类型我们就可以判断两种类型是否相兼容。
infer 用于声明类型变量,以存储在模式匹配过程中所捕获的类型。
条件类型:T extends U ? X : Y
当类型 T 可以赋值给类型 U 时,那么返回类型 X,否则返回类型 Y。
那么条件类型有什么用呢?这里我们来举个例子:
type IsString<T> = T extends string ? true : false; type I0 = IsString<number>; // false type I1 = IsString<"abc">; // true type I2 = IsString<any>; // boolean type I3 = IsString<never>; // never
在以上代码中,我们定义了 IsString 工具类型。使用该工具类型,我们可以判断传给类型参数 T 的实际类型是否为字符串类型。除了判断单一类型之外,利用条件类型和条件链,我们还可以同时判断多种类型。
接下来,我们来看一下如何实现该功能:
type TypeName<T> = T extends string ? "string" : T extends number ? "number" : T extends boolean ? "boolean" : T extends undefined ? "undefined" : T extends Function ? "function" : "object"; type T0 = TypeName<string>; // "string" type T1 = TypeName<"a">; // "string" type T2 = TypeName<true>; // "boolean" type T3 = TypeName<() => void>; // "function" type T4 = TypeName<string[]>; // "object"
如果传入的类型是联合类型的话,那么将返回什么结果
type T10 = TypeName<string | (() => void)>; // "string" | "function" type T11 = TypeName<string | string[] | undefined>; // "string" | "object" | "undefined"
为什么 T10 和 T11 类型返回的是联合类型呢?这是因为 TypeName 属于分布式条件类型。在条件类型中,如果被检查的类型是一个 “裸” 类型参数,即没有被数组、元组或 Promise 等包装过,则该条件类型被称为分布式条件类型。
对于分布式条件类型来说,当传入的被检查类型是联合类型的话,在运算过程中会被分解成多个分支。
T extends U ? X : Y T => A | B | C A | B | C extends U ? X : Y => (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)
关于条件类型,更多查看:《用了 TS 条件类型,同事直呼 YYDS! https://juejin.cn/post/7096265620445986823》
infer:T extends (infer U)[] ? U : T
type U0 = UnpackedArray<T0> // T => T0: string[] type UnpackedArray<string[]> = string[] extends (infer U)[] ? U : string[] // string[] extends (infer U)[] 模式匹配成功 // U => string
infer 只能在条件类型的 extends 子句中使用,同时 infer 声明的类型变量只在条件类型的 true 分支中可用。
当遇到函数重载的场景,TypeScript 将使用最后一个调用签名进行类型推断:
declare function foo(x: string): number; declare function foo(x: number): string; declare function foo(x: string | number): string | number; type UnpackedFn<T> = T extends (...args: any[]) => infer U ? U : T; type U2 = UnpackedFn<typeof foo>; // string | number
利用条件类型和 infer,我们还可以推断出对象类型中键的类型。
type User = { id: number; name: string; } type PropertyType<T> = T extends { id: infer U, name: infer R } ? [U, R] : T type U3 = PropertyType<User> // [number, string]
https://jkchao.github.io/typescript-book-chinese/tips/infer.html
学会 TS infer,写起泛型真香! https://www.51cto.com/article/708480.html
转载本站文章《TS数据类型(2):类型模式匹配技术——条件类型+infer》,
请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/typescript/2022_0923_8877.html