如何推导参数为带可选参数函数的TypeScript重载函数类型
问题解决办法
你遇到的报错是因为 TypeScript 不会自动合并重载签名的参数类型推导到实现函数上,需要你手动给实现的参数标注联合类型,具体方案如下:
方案1:直接标注参数联合类型
给实现函数的arg参数显式标注两种入参的联合类型,同时类型收窄逻辑可以正常工作:
interface OverloadedFn<TArgs> { (args: TArgs): void; (setter: (prev: TArgs) => TArgs): void; } const overloadedFn: OverloadedFn<{ arg1: number }> = (arg: { arg1: number } | ((prev: { arg1: number }) => { arg1: number })) => { if (typeof arg === 'function') { // 此时arg自动收窄为函数类型,可直接调用 const newState = arg({ arg1: 0 }) } else { // 此时arg自动收窄为状态值类型,可直接读取属性 console.log(arg.arg1) } }
方案2:从重载类型提取参数类型(更通用)
如果不想重复写类型,可以直接从定义的重载接口中提取参数类型,避免重复声明:
interface OverloadedFn<TArgs> { (args: TArgs): void; (setter: (prev: TArgs) => TArgs): void; } // 提取重载的入参类型 type OverloadedFnParam<T> = Parameters<OverloadedFn<T>>[0] const overloadedFn: OverloadedFn<{ arg1: number }> = (arg: OverloadedFnParam<{ arg1: number }>) => { if (typeof arg === 'function') { // 逻辑同上 } else { // 逻辑同上 } }
方案3:直接使用函数重载写法(TS 4.7+ 推荐)
如果你的项目TS版本高于4.7,直接用函数声明式重载的写法更简洁,TS可以自动识别:
// 重载签名 function useStateSetter<T>(args: T): void function useStateSetter<T>(setter: (prev: T) => T): void // 实现签名 function useStateSetter<T>(arg: T | ((prev: T) => T)) { if (typeof arg === 'function') { // 处理setter逻辑 } else { // 处理直接传值逻辑 } } // 调用示例,类型自动推导 useStateSetter({ arg1: 1 }) useStateSetter((prev) => ({ arg1: prev.arg1 + 1 }))
内容的提问来源于stack exchange,提问作者RocketMeister
相关产品推荐
相关产品推荐

