Author: dmitripavlutin
Translator: Front-end Xiaozhi Source: dmitripavlutin
If you have dreams and dry goods, you can search for [Great Relocation to the World] on WeChat and pay attention to this Shuwanzhi who is still washing dishes in the early hours of the morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
Most functions accept a fixed set of arguments.
But some functions can take a variable number of arguments, different types of arguments, and even return different types depending on how you call the function. To annotate such functions, TypeScript provides function overloading.
1. Function signature
Let's first consider a function that returns greetings to a specific person.
function greet(person: string): string {
return `Hello, ${person}!`;
}
The above function accepts 1 argument of type character: the person's name. Calling this function is very simple:
greet('World'); // 'Hello, World!'
What if you want to make greet()
function more flexible? For example, have it additionally accept a list of people to greet.
Such a function will accept a string or array of strings as a parameter and return a string or array of strings.
How to annotate such a function? There are 2 methods.
The first method is simple and is to directly modify the function signature by updating the parameters and return type. Here's what it looks like after refactoring greet()
:
function greet(person: string | string[]): string | string[] {
if (typeof person === 'string') {
return `Hello, ${person}!`;
} else if (Array.isArray(person)) {
return person.map(name => `Hello, ${name}!`);
}
throw new Error('Unable to greet');
}
Now we can call greet()
in two ways:
greet('World'); // 'Hello, World!'
greet(['小智', '大冶']); // ['Hello, 小智!', 'Hello, 大冶!']
It is a common good practice to directly update function signatures to support multiple invocation styles.
However, in some cases we may need to take another approach and define separately all the ways your function can be called. This approach is called function overloading .
2. Function overloading
The second way is to use function overloading functions. I recommend this approach when the function signature is relatively complex and involves multiple types.
Defining a function overload requires defining the overload signature and an implementation signature.
An overloaded signature defines the formal parameters and return types of a function, without a function body. A function can have multiple overloaded signatures: corresponding to different ways of calling the function.
On the other hand, an implementation signature also has parameter types and return types, and also the body of the implementing function, and there can only be one implementation signature.
// 重载签名
function greet(person: string): string;
function greet(persons: string[]): string[];
// 实现签名
function greet(person: unknown): unknown {
if (typeof person === 'string') {
return `Hello, ${person}!`;
} else if (Array.isArray(person)) {
return person.map(name => `Hello, ${name}!`);
}
throw new Error('Unable to greet');
}
greet()
function has two overload signatures and one implementation signature.
Each overload signature describes one way in which the function can be called. As far as the greet()
function is concerned, we can call it in two ways: with a string parameter, or with a string array parameter.
The implementation signature function greet(person: unknown): unknown { ... }
contains the appropriate logic for how the function works.
Now, as above, greet()
can be called with an argument of type string or array of strings.
greet('World'); // 'Hello, World!'
greet(['小智', '大冶']); // ['Hello, 小智!', 'Hello, 大冶!']
2.1 Overload signatures are callable
Although the implementation signature implements the function behavior, it cannot be called directly. Only overloaded signatures are callable.
greet('World'); // 重载签名可调用
greet(['小智', '大冶']); // 重载签名可调用
const someValue: unknown = 'Unknown';
greet(someValue); // Implementation signature NOT callable
// 报错
No overload matches this call.
Overload 1 of 2, '(person: string): string', gave the following error.
Argument of type 'unknown' is not assignable to parameter of type 'string'.
Overload 2 of 2, '(persons: string[]): string[]', gave the following error.
Argument of type 'unknown' is not assignable to parameter of type 'string[]'.
In the above example, the ---1c0b2ad28d7788b47a2fd1433ff76448--- function cannot be called with an argument of type unknown (greet(someValue))
even though the implementation signature accepts the unknown
greet()
.
2.1 Implementation signatures must be generic
// 重载签名
function greet(person: string): string;
function greet(persons: string[]): string[];
// 此重载签名与其实现签名不兼容。
// 实现签名
function greet(person: unknown): string {
// ...
throw new Error('Unable to greet');
}
Overloaded signature function greet(person: string[]): string[]
is marked as incompatible with greet(person: unknown): string
.
The return type that implements the signature string
is not generic enough to be compatible with the return type of the overload signature string[]
.
3. Method overloading
Although in the previous example, function overloading was applied to a normal function. But we can also override a method
In the method overloading section, both the overload signature and the implementation signature are part of the class.
For example, we implement a Greeter
class with an overloaded method greet()
.
class Greeter {
message: string;
constructor(message: string) {
this.message = message;
}
// 重载签名
greet(person: string): string;
greet(persons: string[]): string[];
// 实现签名
greet(person: unknown): unknown {
if (typeof person === 'string') {
return `${this.message}, ${person}!`;
} else if (Array.isArray(person)) {
return person.map(name => `${this.message}, ${name}!`);
}
throw new Error('Unable to greet');
}
The Greeter class contains greet()
overloaded methods: 2 overloaded signatures describing how to call the method, and an implementation signature containing the correct implementation
Due to method overloading, we can call hi.greet()
in two ways: with a string or with an array of strings as a parameter.
const hi = new Greeter('Hi');
hi.greet('小智'); // 'Hi, 小智!'
hi.greet(['王大冶', '大冶']); // ['Hi, 王大冶!', 'Hi, 大冶!']
4. When to use function overloading
Function overloading, when used properly, can greatly increase the usability of functions that may be called in multiple ways. This is especially useful when autocompleting: we list all possible overload records in autocompletion.
However, in some cases it is recommended not to use function overloading, but to use function signatures instead.
For example, don't use function overloading for optional parameters:
// 不推荐做法
function myFunc(): string;
function myFunc(param1: string): string;
function myFunc(param1: string, param2: string): string;
function myFunc(...args: string[]): string {
// implementation...
}
It is sufficient to use optional parameters in the function signature:
// 推荐做法
function myFunc(param1?: string, param2: string): string {
// implementation...
}
5. Summary
Function overloading in TypeScript lets us define functions that are called in multiple ways.
Using function overloading requires defining an overload signature: a set of functions with parameters and return types, but no body. These signatures indicate how the function should be called.
Also, you must write out the correct implementation (implementation signature) of the function: parameter and return types, and the function body . Note that the implementation signature is not callable.
In addition to regular functions, methods in classes can also be overloaded.
The bugs that may exist after the code is deployed cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, I recommend a useful bug monitoring tool , Fundebug .
Original: https://dmitripavltin.com/typeript-function-overloading/
comminicate
If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.
This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。