TypeScript如何定义可接收多签名函数作为参数的函数
TypeScript 多签名函数入参的正确类型定义
原写法报错原因
你用函数联合类型定义method参数时报错,核心是TypeScript函数类型的逆变检查规则:当多个函数类型组成联合类型时,TS要求调用该联合函数时传入的参数,必须同时满足所有联合成员的参数要求,才能保证不管运行时传入的是哪个函数,参数都能被正确接收,不会出现参数不匹配的问题。
这种规则下你没法通过bool是否存在来缩小method的类型范围,自然会报参数不匹配的错误。你之前用函数重载没生效,大概率是没有正确拆分重载签名,没有建立bool参数是否存在和method类型之间的绑定关系。
推荐实现方案:函数重载
这是这类场景下最清晰、类型校验最严格的实现方式,核心是把不同参数组合的签名提前声明,内部实现用宽松类型兼容即可,对外暴露的调用约束完全由重载签名控制:
const foo = (a: string, b: number) => { // 业务逻辑 } const bar = (a: number, b: string, c: boolean) => { // 业务逻辑 } // 重载签名1:传入布尔值时,method必须是三参数的bar类型签名 function myDynamicFunction( str: string, method: (a: number, b: string, c: boolean) => void, num: number, bool: boolean ): void // 重载签名2:不传布尔值时,method必须是两参数的foo类型签名 function myDynamicFunction( str: string, method: (a: string, b: number) => void, num: number ): void // 内部实现签名,不对外暴露,用any[]做参数类型兼容即可 function myDynamicFunction( str: string, method: (...args: any[]) => void, num: number, bool?: boolean ) { if (bool) { method(num, str, bool) } else { method(str, num) } } // 合法调用全部校验通过 myDynamicFunction('string', foo, 5) myDynamicFunction('string', bar, 5, true) // 非法调用会被正确拦截 // myDynamicFunction('string', foo, 5, true) // 报错:foo不接收三参数 // myDynamicFunction('string', bar, 5) // 报错:bar缺少第三个必传参数
可选方案:可辨识联合元组参数
如果你不想写重载,也可以通过元组联合的方式定义剩余参数,把method和bool的绑定关系直接定义在元组成员里:
// 定义两种合法的参数组合 type MethodCombo = | [method: (a: string, b: number) => void, bool?: never] | [method: (a: number, b: string, c: boolean) => void, bool: boolean] const myDynamicFunction = ( str: string, num: number, ...[method, bool]: MethodCombo ) => { if (bool) { method(num, str, bool) } else { method(str, num) } }
这个方案的效果和重载基本一致,只是写法上更简洁,适合参数组合更多的场景。
注意:不要在这类参数存在依赖关联的场景下直接用函数联合类型,TS的逆变规则会导致你没法在分支里正确缩小类型,除非你额外写类型断言手动指定
method的类型,但那样会丢失类型安全,不推荐。
内容的提问来源于stack exchange,提问作者RavenHursT
相关产品推荐
相关产品推荐

