我正在阅读 Typescript 手册,我很难理解为什么以下代码片段有错误消息:
function fn(x: string): void;
function fn(vo) {
// ...
}
// Expected to be able to call with zero arguments
fn();
Run Code Online (Sandbox Code Playgroud)
这是解释,但我无法理解,有人可以向我解释这里发生了什么吗?
从外部看不到实现的签名。当编写重载函数时,您应该始终在函数的实现之上有两个或多个签名。
我对此也感到非常困惑。来自Kotlin/Java Android背景,我不得不说 Typescript 的重载机器需要一段时间才能掌握。
overload在 Typescript 中声明我关于处理重载的最初想法是编写以下代码:
function makeDate(timestamp: number): void { /* code */ }
function makeDate(m: number, d: number, y: number): void { /* code */ }
Run Code Online (Sandbox Code Playgroud)
我立即就遇到了Duplicate function implementation.ts(2393)lint 错误。一开始我很困惑,因为这就是 Java 和 Kotlin 中的声明方式overload。然而,这实际上不是你overload在 Typescript 中声明的方式,我相信这是问题的主要原因。
事实证明,在 Typescript 中, 的声明overload不是通过具有相同名称和不同签名的两个方法及其各自的实现来实现的。相反,它首先定义具有相同名称和不同签名但没有主体的方法,最后提供一个具有实现的方法(方法主体),该方法能够处理所有先前声明的无主体方法。
overload[问题的原因]现在我已经找到了在 Typescript 中创建重载方法的正确方法,我直接编写了以下代码:
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")
Run Code Online (Sandbox Code Playgroud)
输出:
$ branch 1
$ branch 2 -> xxx :: yyy :: zzz
Run Code Online (Sandbox Code Playgroud)
在上面的代码片段中,我们声明了1 个具有2 个不同重载的方法。
function fn(x: string): void;function fn(x: string, y: string, z: string): void;
它们都由“具体”方法处理:$ branch 1
$ branch 2 -> xxx :: yyy :: zzz
Run Code Online (Sandbox Code Playgroud)
由于这个方法有一个主体,这就是为什么我称它为具体方法。另请注意,此方法处理 和 的情况@params: x,并且@params: y and z是可选的,通过这样做,它涵盖了方法调用 {overload1和overload2}。这是一个有效的重载。
遵循同样的心态,我继续编写了以下代码:
function fn(x: string, y?: string, z?: string): void {
if (y === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x} :: ${y} :: ${z}`)
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
$ branch 1
$ branch 2 -> x :: y
Run Code Online (Sandbox Code Playgroud)
该代码也有效,正如我所怀疑的那样。所以我又写了一些代码:
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")
Run Code Online (Sandbox Code Playgroud)
但这一次代码不起作用并且tsc抱怨:
Playground.ts:219:5 - error TS2554: Expected 0 arguments, but got 1.
219 fn3("x")
~~~
Found 1 error.
Run Code Online (Sandbox Code Playgroud)
现在我们应该花一些时间来理解文档中的引用:
从外部看不到实现的签名。当编写重载函数时,您应该始终在函数的实现之上有两个或多个签名。
args和signature。所以下面的文字是不正确的。把它留在这里作为一个坏例子。请参阅下面@David 的回答,因为他提供了一个很好的解释,说明为什么这是不正确的。例如:下面附加的代码片段也是具有 0 ~ 1 个参数的有效重载。这可以与产生语法错误的[代码2.3]进行比较。function fn3(): void;
function fn3(x: string): void;
function fn3(x?: string): void {
if (x === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x}`)
}
}
> calling:
fn3()
output:
> [LOG]: "branch 1" // correct behavior
Run Code Online (Sandbox Code Playgroud)
如果您想得太多,这会非常令人困惑,事实证明您可以简单地将其理解为“您必须有 2 个以上的参数才能进行重载”,这就是代码示例[code 2.1]和[code 2.2]工作的原因。自从:
[code 2.1]有1和3 个参数。符合上述文档的要求[code 2.2]它有1和2。这也符合文档中的要求。[code 2.3]它有0和1。这不符合您在文档中函数的实现之上应该始终有两个或多个签名的tsc要求,这就是抱怨的原因。这实际上是有道理的,因为:
$ branch 1
$ branch 2 -> x :: y
Run Code Online (Sandbox Code Playgroud)
与仅使用可选参数定义一个参数相同?:
function fn3(x?: string): void {
if (x === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x}`)
}
}
Run Code Online (Sandbox Code Playgroud)
### 问题 2 的答案:
重载方法声明仅适用于具有 2 个和 2 个以上参数的方法,并且需要一个具有主体的方法来处理您为重载声明的所有情况。另外,这不适用于具有0到1 个参数的方法,在这种情况下tsc会抱怨Expected 0 arguments, but got 1.ts(2554)。同时,为具有0和1 个参数的方法声明重载是多余的,因为您可以只声明具有1 个可选参数的方法。
| 归档时间: |
|
| 查看次数: |
2040 次 |
| 最近记录: |