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

Lys*_*dre 2 overloading type-inference typescript

我目前正在研究 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

要么不带参数调用该函数,要么带两个参数(foo 和 bar)调用该函数。根据 vscode 的智能感知,该result变量的类型为boolean | undefined

为什么bar可以undefined,即使我已经测试foo参数?如果foo存在,类型推断不应该预测它也bar存在吗?

jca*_*alz 5

这里的第一个问题是允许重载函数的实现签名比任何调用签名都宽松。在实现内部,编译器只检查实现签名。这意味着在您的函数内部,foobar都与类型无关,boolean | undefined并且无法恢复这样一个事实,即调用该方法的任何人都将指定两者或两者都不指定。

TypeScript 最近在函数参数中添加了对rest/spread 元组的支持,因此您可以像这样重写函数签名:

declare function method(...args: [] | [boolean, boolean]);   
method(); // okay
method(false); // errror
method(true, false); // okay
Run Code Online (Sandbox Code Playgroud)

现在 TypeScript 知道argstomethod()要么是空元组,要么是一对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
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,推理仍然不起作用,这是第二个问题:TypeScript 的控制流分析根本没有我们那么聪明。虽然我们知道 的类型foo与 的类型相关bar,但编译器没有。如果缩小foo而忘记了,那bar有什么关系foo。解决此问题的一种方法是不分解foobar分成单独的类型,而是在单个args变量上使用属性访问类型保护。当args从 缩小[] | [boolean, boolean]到 just 时[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
    }
}
Run Code Online (Sandbox Code Playgroud)

这可能都是代码更改过多,并且 IntelliSense 对您来说不值得。如果是这样,并且您对编译器更聪明感到自在,您可以只使用类型断言并继续您的一天:

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 
    }
}
Run Code Online (Sandbox Code Playgroud)