在写前端项目时,经常遇到这样的情况:同一个函数要处理不同类型的输入,返回对应的输出。比如一个工具函数,传字符串就返回长度,传数组就返回项数。以前可能会用联合类型加类型断言硬扛,但代码越来越难维护。
ref="/tag/148/" style="color:#B2A89E;font-weight:bold;">条件类型的写法
TypeScript 提供了条件类型,语法看起来像三元表达式:T extends U ? X : Y。意思是如果类型 T 能被赋值给 U,就选 X,否则选 Y。
举个实际例子:有个函数叫 getLength,想让它对字符串和数组都有效,但返回值类型要跟着参数变。
type GetLengthType<T> = T extends string | any[] ? number : never;
function getLength<T>(input: T): GetLengthType<T> {
if (typeof input === 'string' || Array.isArray(input)) {
return input.length as any;
}
throw new Error('Unsupported type');
}
这时候调用 getLength('hello'),TypeScript 知道返回的是 number;传个数字比如 getLength(123),就会提示错误,因为不满足条件。
结合映射类型更实用
在处理接口字段时,经常需要过滤出某些特定类型。比如有这么一个用户数据对象:
interface User {
name: string;
age: number;
isActive: boolean;
}
现在想提取所有布尔类型的字段名,可以这样写:
type BooleanKeys<T> = {
[K in keyof T]: T[K] extends boolean ? K : never;
}[keyof T];
type UserFlags = BooleanKeys<User>; // 结果是 'isActive'
这个技巧在做表单校验、权限控制时特别有用。比如后台返回的配置里哪些是开关字段,可以直接通过类型推导出来,不用手动维护字段列表。
别怕嵌套判断
条件类型支持嵌套,就像 if-else 链。比如要区分原始类型和对象:
type PrimitiveOrObject<T> =
T extends string | number | boolean
? 'primitive'
: 'object';
type A = PrimitiveOrObject<string>; // 'primitive'
type B = PrimitiveOrObject<{ a: 1 }>; // 'object'
这种模式在封装通用组件时很常见。比如一个弹窗组件,根据传入的数据类型决定渲染方式,类型系统能提前帮你把住关。
用熟了之后,会发现条件类型不是花架子,而是真正能减少运行时错误的工具。尤其是团队协作中,别人调用你的方法时,TS 会自动提示“你传错了”,比文档还管用。