如何无需手动指定泛型实现TypeScript条件类型的正确收窄?
TypeScript 泛型联合类型的类型收窄问题
问题场景
你定义了如下类型:
type IInputType = "text" | "checkbox" | "number"; type IField<T extends IInputType> = { name: string; value: T extends "checkbox" ? boolean : T extends "number" ? number : string; type: T; }; // 无法实现正确类型收窄的定义 type IPossibleFieldTypes = IField<IInputType>;
此时存在问题:当变量类型为IPossibleFieldTypes时,即便通过field.type === "checkbox"做类型判断,field.value仍会被识别为string | number | boolean,而非预期的boolean。
但如果手动枚举泛型实例定义联合类型:
// 可正常收窄的手动枚举定义 type IPossibleFieldTypes = | IField<"text"> | IField<"checkbox"> | IField<"number">;
此时类型收窄正常,判断field.type === "checkbox"时,field.value会被正确识别为boolean。
解决方案:利用分布式条件类型自动生成联合类型
无需手动枚举泛型实例,我们可以借助TypeScript的分布式条件类型特性,让联合类型自动展开为对应成员的具体类型。
方法1:通过条件类型触发分发
type IInputType = "text" | "checkbox" | "number"; type IField<T extends IInputType> = { name: string; value: T extends "checkbox" ? boolean : T extends "number" ? number : string; type: T; }; // 自动生成可正确收窄的联合类型 type DistributeField<T extends IInputType> = T extends any ? IField<T> : never; type IPossibleFieldTypes = DistributeField<IInputType>;
方法2:更简洁的写法
// 直接通过infer触发分布式条件类型 type IPossibleFieldTypes = IInputType extends infer U ? IField<U> : never;
原理说明
当条件类型的左侧是裸类型参数(即未被数组、对象等包裹的类型参数),且传入的是联合类型时,TypeScript会自动将联合类型的每个成员单独代入条件类型计算,最终将结果合并为新的联合类型。这样生成的IPossibleFieldTypes和手动枚举的版本完全等价,能够通过type属性实现精准的类型收窄。
验证示例
function handleField(field: IPossibleFieldTypes) { if (field.type === "checkbox") { field.value; // 类型为 boolean } else if (field.type === "number") { field.value; // 类型为 number } else { field.value; // 类型为 string } }
内容的提问来源于stack exchange,提问作者Danilo Cunha
相关产品推荐
相关产品推荐

