TypeScript 函数重载不一致

Posted

技术标签:

【中文标题】TypeScript 函数重载不一致【英文标题】:Inconsistency in TypeScript function overload 【发布时间】:2021-11-20 16:01:42 【问题描述】:

考虑这个例子:

export function fn(arg: string): void;
export function fn(arg: number): void;
export function fn(arg: any) 
    console.log(arg);

所以,fn 可以用字符串或数字来调用。

fn('hello!');
fn(42);

到目前为止,一切都很好。 但随后fn 在不同的地方执行:

function fn2(arg2: string | number) 
    fn(arg2);

在这种情况下,TypeScript 会抱怨:

没有重载匹配这个调用。重载 1 of 2, '(arg: string): void',出现以下错误。

Argument of type 'string | number' is not assignable to parameter of type 'string'.
  Type 'number' is not assignable to type 'string'.   Overload 2 of 2, '(arg: number): void', gave the following error.
Argument of type 'string | number' is not assignable to parameter of type 'number'.
  Type 'string' is not assignable to type 'number'.ts(2769) 

index.tsx(3, 17): 调用会成功 实现,但重载的实现签名不是 外部可见。

有人可以帮我理解这里发生了什么吗?

【问题讨论】:

【参考方案1】:

您可以添加另一个重载

export function fn(arg: string): void;
export function fn(arg: number): void;
export function fn(arg: any): void;
export function fn(arg: any) 
    console.log(arg);


fn('hello!');
fn(42);

function fn2(arg2: string | number) 
    fn(arg2);

Playground

【讨论】:

这为我解决了这个问题,但我不知道为什么。你能解释一下为什么这会为我解决这个问题吗? @ElliotLabsLLC 因为新的重载签名接受任何类型的参数。 所以新的arg:any 参数反映了非重载函数参数,这些参数不计入 Transpiler 函数参数构造? 它只涵盖anything,包括联合类型,在这种情况下为arg2: string | number 因为没有为联合声明重载并且就打字稿而言,numberstring 可以分配给 number | string,但反之则不行【参考方案2】:

重载与联合类型不同。重载定义了“单独的”函数,而联合则允许您将不同的类型作为参数。

// fails
function fn2(arg2: string | number) 

    fn(arg2); // uses the union type


// works 
function fn3(arg2: string | number) 
    
    if(typeof arg2  === 'string') 
        return fn(arg2); // uses string
    
    
    return fn(arg2); // uses number


这意味着fn2 搜索具有string|number 类型参数的函数声明,而fn3 搜索具有string 类型的函数或具有number 类型作为其第一个参数的函数。

如果您确切知道要作为函数参数的类型,则不应使用any

请参阅 documentation 了解联合类型

【讨论】:

以上是关于TypeScript 函数重载不一致的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Typescript 不以正确的方式支持函数重载?

使用枚举重载 TypeScript 函数

Typescript子类函数重载

TypeScript 中的函数重载与使用联合类型

TypeScript 类方法具有与构造函数相同的重载签名

TypeScript 函数重载不一致