我正在阅读Typescript手册,我很难理解为什么下面的代码片段有错误消息:
function fn(x: string): void;
function fn(vo) {
// ...
}
// Expected to be able to call with zero arguments
fn();
这是解释,但我不明白,谁能给我解释一下这是怎么回事?
从外部看不到实现的签名。在编写重载函数时,应该始终在该函数的实现之上具有两个或更多签名。
发布于 2021-07-10 10:30:58
我也对此感到非常困惑。来自Kotlin/Java Android的背景,我不得不说,Typescript的重载机器需要一段时间才能掌握。
首先,我们需要解决如何在Typescript中声明overload
关注点1:声明重载的不正确方式不是问题的原因
关于处理重载,我最初的想法是编写以下代码:
function makeDate(timestamp: number): void { /* code */ }
function makeDate(m: number, d: number, y: number): void { /* code */ }
我马上就被Duplicate function implementation.ts(2393)
的lint错误击中了。一开始我很困惑,因为这是你在Java和Kotlin中声明overload
的方式。然而,这实际上不是你在Typescript中声明overload
的方式,我相信这是问题的主要原因。
对问题1的回答:
事实证明,在Typescript中,overload
的声明不是通过拥有两个具有相同名称和不同签名的方法来实现各自的实现。相反,它首先定义具有相同名称和不同签名的方法,而不是主体,最后提供一个具有实现的方法(方法主体),该方法能够处理所有先前声明的无体方法。
关注点2:overload
要求的参数数量不正确是问题的原因
现在我已经找出了在Typescript中创建重载方法的正确方法,我直接编写了以下代码:
代码2.1
function fn(x: string): void; // <-- Define one way to call method
function fn(x: string, y: string, z: string): void; // <-- Define another way to call method with more param (overloaded way)
function fn(x: string, y?: string, z?: string): void { // <--- provide a method with a body that can handle both previous two declarations
if (y === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x} :: ${y} :: ${z}`)
}
}
fn("x")
fn("xxx", "yyy", "zzz")
输出:
$ branch 1
$ branch 2 -> xxx :: yyy :: zzz
在上面的代码片段中,我们声明了带有2不同重载的1方法。
具体的function fn(x: string): void;
function fn(x: string, y: string, z: string): void;
,它们都是由具体的方法处理的:function fn(x: string, y?: string, z?: string): void {
if (y === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x} :: ${y} :: ${z}`)
}
}
因为这个方法有一个主体,这就是为什么我称它为具体方法。还要注意,此方法处理@params: x
的情况,并且@params: y and z
是可选的,通过这样做,它涵盖了方法调用{overload1
和overload2
}。这是一个有效的重载。
遵循同样的思路,我接着写了下面的代码:
代码2.2
function fn2(x: string): void;
function fn2(x: string, y: string): void;
function fn2(x: string, y?: string): void {
if (y === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x} :: ${y}`)
}
}
fn2("x")
fn2("x", "y")
输出:
$ branch 1
$ branch 2 -> x :: y
代码也可以工作,就像我所怀疑的那样。所以我又写了一些代码:
代码2.3
function fn3(): void;
function fn3(x?: string): void {
if (x === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x}`)
}
}
fn3()
fn3("x")
但这一次代码不起作用,tsc
抱怨道:
Playground.ts:219:5 - error TS2554: Expected 0 arguments, but got 1.
219 fn3("x")
~~~
Found 1 error.
现在,我们应该花一些时间来理解文档中的引用:
从外部看不到实现的签名。在编写重载函数时,应该始终在该函数的实现之上具有两个或更多签名。
如果你想太多了,这是非常令人困惑的,事实证明你可以简单地理解为“你必须有2+参数才能做重载”,这就是为什么代码样例[code 2.1]
和[code 2.2]
有效。因为:
[code 2.1]
它有1和3参数。这符合documentation[code 2.2]
的要求,它有1和2。这也符合[code 2.3]
的docs.tsc
是complaining.的原因
这实际上是有意义的,因为:
function fn3(): void;
function fn3(x?: string): void {
if (x === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x}`)
}
}
与仅使用?
可选参数定义一个参数相同:
function fn3(x?: string): void {
if (x === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x}`)
}
}
所以,对问题2的回答是:
重载方法声明只适用于具有2和2+参数的方法,并且需要一个具有主体的方法来处理您为重载声明的所有情况。此外,这不适用于具有 to 1参数的方法,在这种情况下,tsc
将抱怨Expected 0 arguments, but got 1.ts(2554)
。同时,为带有和1参数的方法声明重载是多余的,因为您可以只使用1可选参数声明一个方法。
https://stackoverflow.com/questions/68213949
复制相似问题