You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现兼容函数联合类型的TypeScript函数包装器?

解决TypeScript函数联合类型包装器的参数类型匹配问题

你的核心问题在于:当泛型TFn被推断为整个FuncUnion联合类型时,Parameters<TFn>[0]会计算出number & string(即never),导致内部调用f(params)时类型不兼容。但实际场景中你需要的是,传入具体的单个函数时,params能自动匹配该函数的参数类型。

下面提供两种可行的解决方法:

方法一:利用分布式条件类型提取参数

通过TypeScript的分布式条件类型,针对联合类型中的每个函数成员单独提取其参数类型,确保params与传入的具体函数参数严格匹配:

type FuncUnion = ((n: number) => string) | ((s: string) => string);

const fnWrapper = <TFn extends FuncUnion>(
  f: TFn,
  params: TFn extends (p: infer P) => string ? P : never
) => {
  f(params as Parameters<TFn>[0]);
};

// 合法调用,类型推断正常
fnWrapper((a: number) => 'r', 2);
fnWrapper((a: string) => 'r', 'hello');

// 传入联合类型函数时会正确报错(符合类型安全要求)
// const f: FuncUnion = Math.random() > 0.5 ? (n: number) => n.toString() : (s: string) => s;
// fnWrapper(f, 123); // 错误:类型“number”不能赋给类型“never”

这里的条件类型TFn extends (p: infer P) => string ? P : never会遍历FuncUnion中的每个成员,分别提取对应的参数类型,避免了联合类型交集导致的never问题。

方法二:使用函数重载

如果FuncUnion的成员数量有限,可以直接为每个成员定义重载签名,让TypeScript根据传入的函数匹配对应的参数类型:

type FuncUnion = ((n: number) => string) | ((s: string) => string);

// 重载签名:对应联合类型中的每个函数
function fnWrapper(f: (n: number) => string, params: number): void;
function fnWrapper(f: (s: string) => string, params: string): void;

// 实现签名:接受联合类型的函数和参数
function fnWrapper(f: FuncUnion, params: number | string) {
  f(params as any);
}

// 合法调用
fnWrapper((a: number) => 'r', 2);
fnWrapper((a: string) => 'r', 'hello');

// 非法调用会被TypeScript拦截
// fnWrapper((a: number) => 'r', 'hello'); // 错误:类型“string”不能赋给类型“number”

这种方式的类型提示更直接,但如果FuncUnion后续扩展新的函数成员,需要同步新增重载签名。

内容的提问来源于stack exchange,提问作者juzie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:23:15