TypeScript如何根据入参是否含null动态推导函数返回类型
实现方案
这个需求完全可以实现,通过TypeScript的类型能力即可精准匹配推导逻辑,不需要额外的类型断言。
原有写法的问题在于将入参类型固定标注为string | null | undefined,TypeScript无法根据调用时传入的实际参数类型做收窄,因此返回值类型会固定为number | null | undefined,无法满足入参无null时返回值也无null的要求。
推荐方案:泛型+分布式条件类型
这个方案灵活度最高,不需要枚举所有入参组合,首先需要确保工具方法isNil带有正确的类型守卫定义,否则TS无法正确识别分支内的类型:
// isNil 类型守卫定义 const isNil = (val: unknown): val is null | undefined => val === null || val === undefined; // 改造后的目标函数 const safeIdCastToNumber = <T extends string | null | undefined>(id: T): T extends string ? number : T => { return isNil(id) ? id : Number(id); };
原理说明
- 定义泛型
T约束为string | null | undefined的子类型,用于捕获调用时传入参数的实际类型 - 返回值使用TypeScript的分布式条件类型做映射:当入参是联合类型时,条件类型会自动遍历联合的每一个成员,将其中的
string类型映射为number,null和undefined类型则原样保留,自然就实现了入参和返回值的null类型联动。
类型验证
可以直接在TS环境中验证推导结果,完全匹配要求:
// 场景1:入参类型为 string | undefined const param1: string | undefined = Math.random() > 0.5 ? '123' : undefined; const res1 = safeIdCastToNumber(param1); // res1 自动推导为 number | undefined,符合预期 // 场景2:入参类型为 string | null | undefined const param2: string | null | undefined = Math.random() > 0.5 ? '123' : Math.random() > 0.5 ? null : undefined; const res2 = safeIdCastToNumber(param2); // res2 自动推导为 number | null | undefined,符合预期 // 场景3:入参为纯string类型 const param3 = '789'; const res3 = safeIdCastToNumber(param3); // res3 自动推导为 number,符合预期
备选方案:函数重载
如果你的入参类型组合是固定的几种,也可以使用TS的函数重载特性实现,写法如下:
const isNil = (val: unknown): val is null | undefined => val === null || val === undefined; // 重载签名,枚举所有入参对应的返回类型 function safeIdCastToNumber(id: string): number; function safeIdCastToNumber(id: string | undefined): number | undefined; function safeIdCastToNumber(id: string | null): number | null; function safeIdCastToNumber(id: string | null | undefined): number | null | undefined; // 函数实现 function safeIdCastToNumber(id: string | null | undefined) { return isNil(id) ? id : Number(id); }
这个方案的缺点是需要手动枚举所有可能的入参组合,后续如果入参类型有扩展,需要同步添加新的重载签名,灵活度低于泛型方案。
内容的提问来源于stack exchange,提问作者agustin37
相关产品推荐
相关产品推荐

