如何在TypeScript中实现带命名参数的函数重载?
我想要实现一个支持两种调用方式的函数:既可以传入普通的位置参数,也可以传入一个包含命名参数的对象。比如不用写myFunc("Foo", null, 111);,直接用myFunc({name:"Foo", age:111});就能传入name和age,无需传递surname。
尝试用TypeScript函数重载实现时,我写了以下代码:
首先定义参数接口:
interface myFuncParams { name: string, surname?: string, age?: number }
然后是重载的函数:
function myFunc({name, surname, age}: myFuncParams): string; function myFunc(name: string, surname?: string, age?: number): string; function myFunc(nameOrObj: string | myFuncParams, surname?: string, age?: number): string { // 业务逻辑 return "" };
但触发了TypeScript错误:
function myFunc({name, surname?, age?}: myFuncParams): string;
// ^: This overload signature is not compatible with its implementation signature. (2394)
function myFunc(name: string, surname?: string, age?: number): string;
function myFunc(nameOrObj: string | myFuncParams, surname?: string, age?: number): string {
// do something and return a string
return ""
};
错误原因
第一个重载签名使用了对象解构语法作为参数,但实现签名的第一个参数是string | myFuncParams。TypeScript无法确认解构出来的surname和age,能和实现签名中作为可选参数的surname、age兼容,导致重载签名与实现签名不匹配。
解决方案
调整第一个重载的参数定义,直接使用myFuncParams类型的单个参数,同时在实现函数内部处理两种参数形式的逻辑:
interface myFuncParams { name: string, surname?: string, age?: number } // 第一个重载:接收命名参数对象 function myFunc(params: myFuncParams): string; // 第二个重载:接收普通位置参数 function myFunc(name: string, surname?: string, age?: number): string; // 实现签名 function myFunc(nameOrObj: string | myFuncParams, surname?: string, age?: number): string { // 统一处理两种参数形式 const { name, surname: funcSurname, age: funcAge } = typeof nameOrObj === 'string' ? { name: nameOrObj, surname, age } : nameOrObj; // 后续业务逻辑示例 return `姓名:${name},姓氏:${funcSurname || '无'},年龄:${funcAge || '未知'}`; }; // 合法调用示例 myFunc({name:"Foo", age:111}); myFunc("Bar", "Doe"); myFunc("Alice", undefined, 30);
这样修改后,重载签名和实现签名的类型完全兼容,同时两种调用方式都能通过TypeScript的类型检查,也满足了业务需求。
内容的提问来源于stack exchange,提问作者Lucas Cohen

