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

时间:2020-04-22 11:53:00

标签: typescript overloading typing

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

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;

请帮助,谢谢

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

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签名。 {(3)}(越来越过时)说:

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

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


无论如何,在这两个签名都返回void的特殊情况下,如果您{{3},则可以将hello重写为const而没有错误。 }与上面的类型相同:

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

在这种情况下,无论如何要使用的方法是使用TypeScript spec而不是注释:

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

该编译没有错误。


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

annotate