如何让TypeScript根据判别式参数正确推断其他函数参数?
实现TypeScript参数关联类型推断
先看你给出的原始代码问题:
type ATrue = (a: true, b: number) => void; type AFalse = (a: false, b: string) => void; const fromUnion: ATrue | AFalse = (a, b) => { if (a) { b; // any } else { b; // any } }; const fromIntersection: ATrue & AFalse = (a, b) => { if (a) { b; // number | string } else { b; // number | string } };
当前TypeScript的推断结果如注释所示:fromUnion中b被推断为any,fromIntersection中b被推断为number | string,无法根据a的布尔值自动关联b的类型。
解决方案
1. 使用函数重载(最直观方式)
函数重载可以明确声明不同参数组合对应的类型,TypeScript能正确根据a的值窄化b的类型:
// 重载签名:定义不同参数组合的类型约束 function handleArgs(a: true, b: number): void; function handleArgs(a: false, b: string): void; // 实现签名:编写函数逻辑 function handleArgs(a: boolean, b: number | string): void { if (a) { b; // 类型为number,可安全调用number方法如toFixed console.log(b.toFixed(2)); } else { b; // 类型为string,可安全调用string方法如toLowerCase console.log(b.toLowerCase()); } }
2. 泛型结合条件类型
通过泛型约束和条件类型,让b的类型完全依赖于a的布尔值:
type ConditionalFn<T extends boolean> = ( a: T, b: T extends true ? number : string ) => void; const handleArgs: ConditionalFn<boolean> = (a, b) => { if (a) { b; // number } else { b; // string } };
3. 基于原有类型构建区分联合参数
如果需要保留ATrue和AFalse的定义,可以提取它们的参数类型组成区分联合类型,再用于函数定义:
type ATrue = (a: true, b: number) => void; type AFalse = (a: false, b: string) => void; // 提取两个函数的参数类型,组成区分联合 type ArgsUnion = Parameters<ATrue> | Parameters<AFalse>; const handleArgs: (...args: ArgsUnion) => void = (a, b) => { if (a) { b; // number } else { b; // string } };
为什么原有方式不行?
- 函数联合类型:TypeScript对函数联合的参数处理遵循逆变原则,要求传入的参数能满足所有联合分支的参数要求,因此内部无法通过
a的值窄化b的类型,只能推断为any。 - 函数交叉类型:交叉后的函数要求参数同时满足两个原始函数的参数,
a的类型会被推断为true & false(即never),b则是number | string,自然无法区分类型。
内容的提问来源于stack exchange,提问作者vividn
相关产品推荐
相关产品推荐

