重载的语法
在ts中,一个函数拥有多个签名的写法被称为函数的重载。熟悉Java的人很容易理解,重载就是一个function在传入不同的参数时拥有特定的不同的返回值。比如下面这个函数:
function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
请注意,function pickCard(x): any并不是重载列表的一部分,因此这里只有两个重载:一个是接收对象另一个接收数字。 以其它参数调用pickCard会产生错误。
这样做的好处主要有以下几点:
- 提高代码的可读性和可维护性。
- 增强代码的灵活性:函数重载允许我们使用相同的函数名,但传入不同数量或不同类型的参数,从而创建出多个方法或产生不同的结果。
- 提供类型安全:TypeScript 的类型系统会在编译时检查函数的使用是否符合其定义的重载列表,从而提供类型安全。
和联合类型的区别
我们可能会有这种疑问,上面的例子我们完全可以写成:
function pickCard(x: {suit: string; card: number; }[] | number): number | {suit: string; card: number; } {
// Check to see if we're working with an object/array
// if so, they gave us the deck and we'll pick the card
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
// Otherwise just let them pick the card
else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
那么重载的本质是什么呢?
- 重载:
function f1(a: string) { }
function f1(a: number) { }
function f1(a: any) : any {}
- 联合类型:
function f1(a: string | number):string | number { }
其实答案就是: 对于函数参数类型,函数重载可以比联合类型和泛型类型更具体。
函数重载将特定的输入类型映射到特定的返回类型。使用联合,我们只知道返回是有效类型之一,但是失去了输入和输出之间的关联。这可能是问题,也可能不是问题,这取决于使用函数的方式和位置。但这就是不同之处。
函数重载允许我们为不同的参数类型定义不同的行为,而且每个重载都有一个明确的返回类型。这意味着,我们可以根据参数类型来确定返回类型,这是联合类型无法做到的。
对于上面的例子,调用f1,我们得到的return type永远是 stirng | number, 失去了特异性。
泛型
还有第三个选项是typescript generics。这允许我们在接受无限多类型的同时保持特异性。我们告诉typescript“查看参数a的类型,并将其称为T”。然后我们得到这个类型变量T,我们可以在返回类型中使用它。在这里,我们只是直接返回相同类型的T,但是你可以用它做更多的事情。
function generic<T>(a: T): T {
return a;
}
const bool = generic<boolean>(false) // bool会被推导为boolean类型