TypeScript allows the definition of overloaded function types, which can be implemented in the form of multiple consecutive overloaded declarations + one function implementation. for example
function func(n: number): void;
function func(prefix: string, n: number): void;
function func(first: string | number, n?: number): void {
if (typeof first === "string") {
console.log(`${first}-${n}`);
} else {
console.log(`number-${first + 10}`);
}
}
func()
function in the example has two overloads:
(number) => void
(string, number) => void
In its implementation part, the parameter and return value declarations must be compatible with all overloads, so the first parameter may be number
or string
or first: string | number
; and the second parameter may be number
or none, which is n?: number
.
The declaration of overloaded functions can be defined by the interface declaration of the function. The above overloaded function type can be defined as follows:
interface Func {
(n: number): void;
(prefix: string, n: number): void;
}
Check it out:
const fn: Func = func;
The above is "Preface"!
Now, forget about func()
, we have two functions defined separately func1()
and func2()
:
function func1(n: number): void {
console.log(`number-${n + 10}`);
}
function func2(prefix: string, n: number): void {
console.log(`${prefix}-${n}`);
}
And there is a render()
, hope to render the output according to the function passed in:
function render(fn: Func): void {
if (fn.length === 2) {
fn("hello", 9527);
} else {
fn(9527);
}
}
So far, everything has been fine. Next is the test render()
render(func1);
render(func2);
The problem is, whether it is func1
or func2
, it can not match the parameter type of render()
! !
There is a misunderstanding that many people understand the overloaded function type. They think that if the function f
conforms to an overloaded signature of the overloaded function type Fn
, then it should be used as this overloaded type.
In fact, if a function is to match the overloaded function type, then it must also be an overloaded function (or a function compatible with all overloaded types). Take the above example, if you pass in func1
, render()
can indeed accurately enter the else
branch when running, and successfully call fn(9527)
; passing in func2
can also accurately enter the if
branch and successfully call fn("hello", 9527)
. but--
These things are done by JavaScript at runtime. The TypeScript compiler, static analysis at the time of discovery render()
parameters fn
need to be compatible fn(string, number)
calls and fn(number)
call, whether func1()
or func2()
do not have all the conditions.
So in the above example, render()
can only be the overloaded function func
but not func1
or func2
.
So what if you want to achieve the original purpose?
Suppose types Func1
and Func2
are func1()
and func2()
types, this render()
function should be so declared:
function render(fn: Func1 | Func2) { ... }
But in this way, the render()
function will not work, because fn
is one of the two types, but it is not sure which one is when it is called. We need to write a type assertion function to help TypeScript inference. The complete example is as follows:
type Func1 = (n: number) => void;
type Func2 = (prefix: string, n: number) => void;
function isFunc2(fn: Func1 | Func2): fn is Func2 {
return fn.length === 2;
}
function render(fn: Func1 | Func2): void {
if (isFunc2(fn)) {
fn("hello", 9527);
} else {
fn(9527);
}
}
render(func1); // number-9527
render(func2); // hello-9527
Finally, to summarize and emphasize: overloaded function type and the combination function types participating in the overloaded type are completely different two types, please pay attention to the difference, do not misuse.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。