如何为打字稿中的const定义重载签名?

问题描述 投票:0回答:2

我们可以在打字稿中定义像这样的重载函数:

function hello(name: number): void;
function hello(name: string): void;
function hello(name: number | string): void {
  // ...
}

我试图将此函数定义为const,例如:

const hello = (name: number | string): void => {
  // ...
}

但不确定如何在其上声明过载签名:

(name: number): void; 
(name: string): void;

请帮助,谢谢

typescript overloading typing
2个回答
1
投票

鉴于您的overloaded函数语句hello,您可以通过将type alias写入其类型并通过将其悬停在IDE中并通过IntelliSense进行检查来发现编译器自己为其推断的类型:

type Hello = typeof hello;
/* type Hello = {
    (name: number): void;
    (name: string): void;
} */

在这里您可以看到Hello被认为是具有两个call signatures的对象类型,它们代表您在过载列表中以相同顺序声明的呼叫签名。

您还可以将等效类型写为功能类型的intersection

type AlsoHello = ((name: string) => void) & ((name: number) => void);

[如果您具有F1F2功能类型,则F1 & F2表示重载功能,其中在F1签名之前先检查F2签名。在(越来越过时的)TypeScript spec中,它说:

虽然A & B等同于B & A通常是正确的,但是在确定调用并构造交叉点类型的签名时,构成类型的顺序可能很重要。

在其余的答案中,我将使用带有多个调用签名的对象类型版本,而不是使用箭头功能签名的交集版本。


无论如何,在这两个签名都返回void特殊情况下,如果使用上述类型的hello,则可以将其const重写为annotate,没有错误:

const helloConst: {
  (name: number): void;
  (name: string): void;
} = (name: number | string): void => {
  // ...
}

尽管,一般情况下要注意...重载函数语句的检查不如const赋值严格。重载的函数语句允许实现签名的返回类型匹配调用签名的返回类型的并集,即使这样做并不安全:

function goodbye(name: number): number;
function goodbye(name: string): string;
function goodbye(name: number | string): number | string {
  return typeof name === "number" ? name + 1 : name + "!";
}

以上没有编译器错误。 goodbye()的实现返回number | string,您可以将typeof name === "number"更改为typeof name !== "number",编译器仍然不会警告您。通常认为这是功能而非错误。

但是现在,如果您将其写为const,则会出现错误:

const goodbyeConst: { // error!
  (name: number): number;
  (name: string): string;
} = (name: number | string): number | string =>
    typeof name === "number" ? name + 1 : name + "!";
// Type '(name: string | number) => string | number' 
// is not assignable to 
// type '{ (name: number): number; (name: string): string; }'.

const分配被更严格地检查,并且编译器(正确)抱怨您不能安全地将(name: string | number) => string | number类型的函数视为((name: string) => string) & ((name: number) => number)类型的函数。毕竟,实现总是可以返回满足实现签名但无法与string调用签名匹配的number

无论如何,在这种情况下,要使用type assertion而不是注释:

const goodbyeConstAssert = ((name: number | string): number | string =>
  typeof name === "number" ? name + 1 : name + "!") as { // error!
    (name: number): number;
    (name: string): string;
  }

该编译没有错误。


好的,希望能有所帮助;祝你好运!

Playground link to code


1
投票

您可以使用可调用的签名定义类型/接口,并使用它来键入变量:

type Hello = {
    (name: number): void,
    (name: string): void,
}

const hello: Hello = (name: number | string): void => {
    // ...
}

hello(1); // ok
hello('1'); // ok

declare const wrong: string | number;
// @ts-expect-error
hello(wrong)

Playground

© www.soinside.com 2019 - 2024. All rights reserved.