首页 > 解决方案 > 打字稿中的重载签名和实现签名

问题描述

我正在阅读 Typescript 手册,我很难理解为什么以下代码片段有错误消息:

function fn(x: string): void;
function fn(vo) {
  // ...
}
// Expected to be able to call with zero arguments
fn();

这是解释,但我无法理解,有人可以向我解释这里发生了什么吗?

从外部看不到实现的签名。在编写重载函数时,您应该始终在函数实现之上有两个或多个签名。

标签: typescript

解决方案


我也对此感到非常困惑。来自Kotlin/Java Android背景,不得不说 Typescript 的重载机器需要一段时间才能掌握。

首先,我们需要解决如何overload在 Typescript中声明

问题 1:声明重载的方法不正确 [不是问题的原因]

我最初关于处理重载的想法是编写以下代码:

function makeDate(timestamp: number): void { /* code */ }
function makeDate(m: number, d: number, y: number): void { /* code */ }

我立即被Duplicate function implementation.ts(2393)lint 错误击中。一开始我很困惑,因为这是你overload在 Java 和 Kotlin 中声明的方式。但是,这实际上不是您overload在 Typescript 中声明的方式,我相信这是问题的主要原因。

对问题 1 的回答:

事实证明,在 Typescript 中,声明overload不是通过使用两个具有相同名称和不同签名的方法来实现它们各自的实现。而是先定义同名不同签名的方法,没有body,最后提供一个有实现的方法(方法体),它能够处理所有之前声明的bodyless方法。

问题 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

在上面的代码片段中,我们声明了1 个具有2 个不同重载的方法。

  1. 过载 1 ->function fn(x: string): void;
  2. 重载2 - >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是可选的,这样做它涵盖了方法调用 {overload1overload2}。这是一个有效的重载。

遵循相同的心态,然后我继续编写以下代码:

[代码 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+ args 才能进行重载”,这就是代码示例[code 2.1][code 2.2]工作的原因。自从:

  • 对于[code 2.1]它有13 个参数。符合上述文件的要求
  • 因为[code 2.2]它有12。这也符合文档中的要求。
  • 但是,因为[code 2.3]它有01。这不符合您应该始终在文档中的函数实现之上有两个或多个签名tsc的要求,这就是抱怨的原因。

这实际上是有道理的,因为:

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+ 个参数的方法,并且需要具有主体的方法来处理您为重载声明的所有情况。此外,这不适用于具有01 个参数的方法,在这种情况下tsc会抱怨Expected 0 arguments, but got 1.ts(2554)同时,为具有01 个参数的方法声明重载是多余的,因为您可以只声明具有1 个可选参数的方法。


推荐阅读