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