TypeScript 条件类型
介绍
TypeScript 的条件类型(Conditional Types)是一种强大的工具,它允许我们根据类型之间的关系动态选择类型。条件类型的语法类似于 JavaScript 中的三元运算符,但它作用于类型层面。通过条件类型,我们可以编写更加灵活和可重用的类型定义。
条件类型的基本语法如下:
T extends U ? X : Y
其中:
T
是一个类型。U
是另一个类型。- 如果
T
可以赋值给U
,则条件类型的结果为X
,否则为Y
。
基本用法
让我们从一个简单的例子开始,了解条件类型的基本用法。
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
在这个例子中,IsString
是一个条件类型,它检查 T
是否是 string
类型。如果是,则返回 true
,否则返回 false
。
条件类型与泛型
条件类型通常与泛型结合使用,以便在更复杂的场景中动态选择类型。例如,我们可以创建一个类型,根据输入类型的不同返回不同的类型。
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? "boolean"
: "object";
type A = TypeName<string>; // "string"
type B = TypeName<number>; // "number"
type C = TypeName<boolean>; // "boolean"
type D = TypeName<object>; // "object"
在这个例子中,TypeName
类型根据 T
的类型返回不同的字符串字面量类型。
分布式条件类型
当条件类型作用于联合类型时,TypeScript 会将条件类型“分发”到联合类型的每个成员上。这种行为称为分布式条件类型。
type ToArray<T> = T extends any ? T[] : never;
type A = ToArray<string | number>; // string[] | number[]
在这个例子中,ToArray
类型将联合类型 string | number
转换为 string[] | number[]
。
分布式条件类型只在 T
是裸类型参数(即没有包裹在数组、元组等结构中)时生效。
实际应用场景
条件类型在实际开发中有许多应用场景。以下是一些常见的例子:
1. 过滤联合类型
我们可以使用条件类型从联合类型中过滤出特定的类型。
type Filter<T, U> = T extends U ? T : never;
type A = Filter<string | number | boolean, string | boolean>; // string | boolean
在这个例子中,Filter
类型从 string | number | boolean
中过滤出 string | boolean
。
2. 提取函数返回类型
我们可以使用条件类型提取函数的返回类型。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function foo() {
return 42;
}
type A = ReturnType<typeof foo>; // number
在这个例子中,ReturnType
类型提取了函数 foo
的返回类型 number
。
3. 递归条件类型
条件类型可以递归地应用于自身,以处理更复杂的类型转换。
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
type A = DeepReadonly<{ a: number; b: { c: string } }>;
// { readonly a: number; readonly b: { readonly c: string } }
在这个例子中,DeepReadonly
类型递归地将对象的所有属性设置为只读。
总结
TypeScript 的条件类型为我们提供了一种强大的工具,可以根据类型之间的关系动态选择类型。通过条件类型,我们可以编写更加灵活和可重用的类型定义,从而提升代码的可维护性和可读性。
在实际开发中,条件类型可以用于过滤联合类型、提取函数返回类型、递归地处理复杂类型等场景。掌握条件类型的使用,将有助于你编写更加高效和健壮的 TypeScript 代码。
附加资源
练习
- 创建一个条件类型
IsArray<T>
,检查T
是否是数组类型。 - 使用条件类型实现一个
NonNullable<T>
类型,从T
中移除null
和undefined
。 - 创建一个递归条件类型
Flatten<T>
,将嵌套数组类型扁平化。
通过完成这些练习,你将进一步巩固对条件类型的理解。