【问题标题】:Typescript overloads, optional arguments and type inference打字稿重载、可选参数和类型推断
【发布时间】:2019-09-15 01:58:49
【问题描述】:

我目前正在研究 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 的智能感知,result 变量的类型为 boolean | undefined

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

【问题讨论】:

标签: typescript overloading type-inference


【解决方案1】:

这里的第一个问题是允许重载函数的实现签名比任何调用签名都宽松。在实现内部,编译器只检查实现签名。这意味着在您的函数内部,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 ?
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-22
    • 1970-01-01
    • 2018-06-09
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 2020-04-02
    相关资源
    最近更新 更多