Typescript 中的函数重载
Typescript 是一种建立在 Javascript 之上的类型系统,其唯一目的是通过应用强类型安全性来保护您的应用程序。
借助 Typescript,您可以通过在构建时捕获错误来减少运行时错误。作为一名优秀的团队成员,在创建实用程序函数时创建强类型函数会很有帮助。这样做,自动补全和类型推断将在您的队友使用您的函数时为您提供帮助,并减少错误。
让我们通过一种称为函数重载的技术来看看如何实现这一点。
在此示例中,我们旨在创建具有以下功能的函数:
- 通过检查每个元素是否以指定的搜索参数开头来过滤字符串数组。
- 选择返回第一个匹配项或所有匹配的元素。
- 检查给定的字符串是否以搜索参数开头
下面的函数演示了如何实现这些条件:
function select(arr: string[] | string, search: string, firstOnly = false){
// ^? string | boolean | string[] | undefined
if(Array.isArray(arr)){
return firstOnly
? arr.find(a => a.startsWith(search))
: arr.filter(a => a.startsWith(search))
}else {
return arr.startsWith(search);
}
}
注:实现细节不是本文的重点。
现在,让我们调用此函数来返回与搜索参数匹配的所有元素:
const names = ['toto', 'jack', 'robert'];
const t = filter(names, 'to');
// ^? string | boolean | string[] | undefined
问题:推断的返回类型是string | boolean | string[] | undefined
。Typescript 无法将返回类型缩小到 string[],即使我们知道这是唯一可能的返回类型。
在第二个示例中,如果我们想使用函数检查给定的字符串是否与搜索参数匹配,Typescript 允许我们设置该firstOnly
参数,但这在我们的情况下是无用且令人困惑的。
为了解决这些问题,我们可以重载filter
函数。重载是指定义同一函数的多个版本,并使其具有不同的参数类型和返回类型。
在这个例子中,我们定义了三个不同版本的过滤函数:
function filter(arr:string[], search: string): string[];
function filter(arr:string[], search: string, firstOnly: true): string | undefined;
function filter(elt:string, search: string): boolean;
function filter(arr: string[] | string, search: string, firstOnly = false){
if(Array.isArray(arr)){
return firstOnly ? arr.find(a => a.startsWith(search)): arr.filter(a => a.startsWith(search))
}else {
return arr.startsWith(search);
}
}
第一个版本接受一个字符串数组和一个搜索参数,并返回一个匹配字符串的数组。第二个版本添加了一个firstOnly
参数,当设置为 时true
,仅返回第一个匹配的字符串,如果未找到匹配项,则返回 undefined。第三个版本接受一个字符串和一个搜索参数,并返回一个布尔值,指示该字符串是否以搜索参数开头。
函数的实现filter
会将所有定义连接成一个。但是,这个组合定义不能直接在代码中使用。如果我们想filter
以字符串作为第一个参数调用该函数,并以布尔值作为最后一个参数,则需要添加一个新的函数定义。
重载filter
函数有几个好处:
firstOnly
仅当第一个参数为数组时才可以设置该参数。- 根据函数的参数,推断的类型正确缩小。
例子:
该图显示了 Typescript 抛出的错误,因为我们已经设置了firstOnly
参数,但我们的第一个参数是 a,string
并且没有函数定义与此实现匹配。
const names = ['toto', 'jack', 'robert'];
const first = filter(names, 'to', true);
// ^? string | undefined
const second = filter(names, 'to');
// ^? string[]
const third = filter('toto', 'to')
// ^? boolean
函数调用具有良好的自动完成和类型推断功能,使得filter
函数的使用更加容易。
警告:然而,仍然有一个重要的警告需要考虑。
虽然函数调用变得更加安全,但我们在实现内部却失去了所有类型安全性。TypeScript 告诉我们我们比它更了解类型,如果我们的定义不正确,TypeScript 就不会保护我们。
让我们用一个例子来说明这个警告,说明我们如何通过谎报功能的行为来欺骗我们的团队成员:
function lying(elt:string): number;
function lying(elt:number): string;
function lying(elt: string | number){
return elt;
}
const t = lying('toto');
// ^? number
上面的代码中,函数很简单,但却完美地演示了问题所在。我们设置了两个 TypeScript 信任的定义,但正如我们所见,返回类型不正确。调用该函数时,推断出的 t 类型不正确。
虽然函数重载非常有用,但务必谨慎,确保类型尽可能准确。有时候,类型准确度较低总比欺骗用户要好。
希望以上内容能帮助您了解 Typescript 中的函数重载!这确实是一项高级功能,但它在提升代码安全性和可靠性方面非常有用。记住,使用函数重载时务必谨慎,因为如果不谨慎使用,可能会导致类型安全问题。
祝你的 Typescript 项目一切顺利,如果有任何其他问题,请随时联系我!你可以在Twitter或Github上找到我。
文章来源:https://dev.to/this-is-angular/function-overloading-in-typescript-53eb