如何将联合类型约束为特定类型?解决TypeScript函数apply报错
以下是用户提供的代码:
type MyMap = { a: () => void b: (s: string) => void c: (n: number) => void } type MyKey = keyof MyMap function wrapper(fn: MyMap[MyKey]) { return async function(...arg: Parameters<MyMap[MyKey]>) { await Promise.resolve(); fn.apply(null, arg); } }
运行时TypeScript抛出错误:
The 'this' context of type '(() => void) | ((s: string) => void) | ((n: number) => void)' is not assignable to method's 'this' of type '(this: null) => void'.
Type '(s: string) => void' is not assignable to type '(this: null) => void'.
Target signature provides too few arguments. Expected 1 or more, but got 0.
用户认为逻辑上fn与arg匹配,需要解决该类型报错。
报错原因
问题核心在于联合类型的函数调用限制:MyMap[MyKey]是三个函数的联合类型,Parameters<MyMap[MyKey]>会生成[] | [string] | [number]的联合参数列表。TypeScript对联合类型函数的调用有严格规则——只有当传入的参数能被所有联合成员接受时才合法,显然这里无法满足(比如给需要string的函数传空参数不被允许),同时apply的this绑定也因联合类型签名不兼容触发报错。
解决方案:泛型约束实现类型安全匹配
通过泛型捕获具体的键类型,让函数与参数列表严格对应,避免使用模糊的联合类型:
type MyMap = { a: () => void b: (s: string) => void c: (n: number) => void } type MyKey = keyof MyMap function wrapper<K extends MyKey>(fn: MyMap[K]) { return async function(...arg: Parameters<MyMap[K]>) { await Promise.resolve(); fn.apply(null, arg); } }
原理说明
泛型K会锁定传入fn对应的具体键(比如'a'、'b'或'c'),此时MyMap[K]变为单个确定的函数类型,Parameters<MyMap[K]>也会对应生成该函数的参数列表。fn与arg的类型完全匹配,TypeScript能正确完成类型校验,报错自然消除。
备选方案:类型断言(不推荐)
若暂时不想使用泛型,可通过类型断言跳过类型检查,但这会丢失TypeScript的类型安全保障:
function wrapper(fn: MyMap[MyKey]) { return async function(...arg: Parameters<MyMap[MyKey]>) { await Promise.resolve(); (fn as (...args: any[]) => void).apply(null, arg); } }
内容的提问来源于stack exchange,提问作者Zhou TK

