TypeScript泛型函数内typeof类型守卫无法调用函数类型参数问题
问题产生原理
TypeScript 内置的 typeof v === "function" 类型守卫,只有当联合类型的成员和函数类型完全互斥时,才会执行收窄逻辑。
在非泛型版本的示例中,参数类型是 string | (() => string):string 是原始类型,不可能是函数,所以当判断 typeof param === "function" 成立时,TS 可以100%确定param是后者即() => string类型,允许直接调用。
但在泛型版本中,参数类型是 T | (() => T):泛型参数T可以被实例化为任意类型,包括函数类型。比如当你传入T = () => number时,参数类型会展开为(() => number) | (() => () => number),此时两个分支都是函数类型,typeof判断无法区分你拿到的是「需要调用的取值函数」还是「本身就是返回值的函数」,TS 出于类型安全考虑不会自动收窄类型,就会报调用异常。
可行修复方案
你可以根据自己的场景选以下任意一种方案:
- 方案1:直接使用类型断言(最简洁,适合逻辑确定无歧义的场景)
明确告诉TS此时param的类型就是返回T的函数:function func<T>(param: T | (() => T)) { return typeof param === "function" ? (param as () => T)() : param; } - 方案2:封装自定义类型守卫
把收窄逻辑抽成类型谓词,让TS明确收窄规则:function isLazyValue<T>(val: T | (() => T)): val is () => T { return typeof val === "function"; } function func<T>(param: T | (() => T)) { return isLazyValue(param) ? param() : param; } - 方案3:使用函数重载
提前明确两种入参对应的返回类型,TS在实现体中可以正确推导:// 重载签名 function func<T>(param: () => T): T; function func<T>(param: T): T; // 实现签名 function func<T>(param: T | (() => T)) { return typeof param === "function" ? param() : param; }
内容的提问来源于stack exchange,提问作者tsbeginner
相关产品推荐
相关产品推荐

