Typescript重载,可选参数和类型推断

问题描述 投票:1回答:1

我目前正在寻找Typescript中的重载。

假设我有一个带有一个重载的函数:

function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(foo?: boolean, bar?: boolean) {
    if (foo === true || foo === false) {
        const result = bar;
    }
}

函数是在没有参数的情况下调用的,或者是用两个参数调用的(foo和bar)。根据vscode的intellisense,result变量有一种boolean | undefined

即使我测试了bar参数,为什么undefined可以成为foo?如果fooexists,不应该类型推断预测barexists也?

typescript overloading type-inference
1个回答
3
投票

这里的第一个问题是允许重载函数的实现签名比任何调用签名更松散。在实现中,编译器仅检查实现签名。这意味着在你的函数内部,foobar都独立于boolean | undefined类型,并且没有办法恢复调用该方法的任何人都指定两者或两者都没有的事实。

TypeScript最近添加了对rest/spread tuples in function parameters的支持,因此您可以像这样重写您的函数签名:

declare function method(...args: [] | [boolean, boolean]);   
method(); // okay
method(false); // errror
method(true, false); // okay

现在TypeScript知道argsmethod()要么是空元组,要么是一对boolean值。如果需要,可以保留重载,只需使实现签名更窄:

function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(...args: [] | [boolean, boolean]) {
  const foo = args[0];
  const bar = args[1];
  if (foo === true || foo === false) {
    const result = bar; // oops, still boolean | undefined
  }
}

不幸的是,推理仍然不起作用,这是第二个问题:TypeScript的控制流分析并不像我们那样聪明。虽然我们知道foo的类型与bar的类型相关,但编译器却没有。如果缩小foo但忘记了barfoo有任何关系。修复此问题的一种方法是不将foobar拆分为单独的类型,而是在单个args变量上使用属性访问类型保护。当args[] | [boolean, boolean]缩小到[boolean, boolean]时,你可以确定定义了第二个元素:

function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(...args: [] | [boolean, boolean]) {    
    if ('0' in args) {
        const result = args[1]; // boolean
    }
}

这可能都是代码更改太多,而IntelliSense对您来说并不值得。如果是这样,并且你觉得编译器更聪明,你可以使用type assertion继续你的一天:

function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(foo?: boolean, bar?: boolean) {
    if (foo === true || foo === false) {
        const result = bar as boolean; // I'm smarter than the compiler 🤓
    }
}

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

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