【问题标题】:TypeScript never type inferenceTypeScript 从不类型推断
【发布时间】:2017-03-08 04:26:20
【问题描述】:

有人可以解释一下为什么给出以下代码:

let f = () => {
    throw new Error("Should never get here");
}

let g = function() { 
    throw new Error("Should never get here");
}

function h() { 
    throw new Error("Should never get here");
}

推断出以下类型:

  • f() => never
  • g() => never
  • h() => void

我希望h 的类型也是() => never

谢谢!

【问题讨论】:

    标签: typescript types type-inference


    【解决方案1】:

    很好的问题。区别在于fg 是函数表达式,而h 是函数声明。当一个函数是 throw-only 时,如果它是一个表达式,它会得到类型 never,如果它是一个声明,它会得到 void

    当然,上面的段落实际上并没有帮助。为什么函数表达式和函数声明之间的行为存在差异?让我们看一下每种情况下的一些反例。

    坏主意 #1:让 throwing 函数表达式返回 void

    考虑一些代码:

    function iif(value: boolean, whenTrue: () => number, whenFalse: () => number): number {
        return value ? whenTrue() : whenFalse();
    }
    let x = iif(2 > 3,
      () => { throw new Error("haven't implemented backwards-day logic yet"); },
      () => 14);
    

    这段代码可以吗?它应该是!当我们认为不应调用该函数或仅应在错误情况下调用该函数时,通常会编写 throwing 函数。但是,如果函数表达式的类型是 void,则对 iif 的调用将被拒绝。

    所以从这个例子中可以清楚地看出,只有throw 的函数表达式应该返回never,而不是void。实际上这应该是我们的默认假设,因为这些函数符合 never 的定义(在正确类型的程序中,无法观察到 never 类型的值)。

    坏主意 #2:让 throwing 函数声明返回 never

    读完上一节后,你应该说“太好了,为什么不是所有的抛出函数都返回never?”

    简短的回答是,这样做是一个重大的突破性变化。有很多看起来像这样的代码(尤其是 abstract 关键字之前的代码)

    class Base {
        overrideMe() {
            throw new Error("You forgot to override me!");
        }
    }
    
    class Derived extends Base {
        overrideMe() {
            // Code that actually returns here
        }
    }
    

    但是返回 void 的函数不能替换返回 never 的函数(请记住,在正确类型的程序中,never 的值是无法观察到的),因此使 Base#overrideMe 返回 never防止Derived 提供该方法的任何非never 实现。

    通常,虽然总是抛出的函数表达式经常作为Debug.fail的占位符存在,但总是抛出的函数声明非常罕见。表达式经常得到别名或忽略,而声明是静态的。一个函数声明,今天throws 实际上明天可能会做一些有用的事情;在没有返回类型注释的情况下,提供更安全的东西是void(即暂时不要查看此返回类型)而不是never(即此函数是一个黑洞,会吃掉当前的执行堆栈)。

    【讨论】:

    • 非常感谢您的帮助 :) 您是否认为所有的投掷函数将来都不会返回?
    • 你总是可以在函数声明中添加一个显式的永不返回类型。
    • 坏主意 #3:尝试在 JS 中做基于类的 OOP ?
    猜你喜欢
    • 2018-07-03
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 1970-01-01
    • 1970-01-01
    • 2017-10-04
    相关资源
    最近更新 更多