在看看TypeScript 2.0中的新功能时,我发现了never
类型。根据文档,似乎这是一种设置永不返回的函数类型的聪明方法。
现在,如果我正确读取所有内容,那么never
可以分配给每种类型,但只有never
可以分配给never
。因此,在VS Code中编写一个小测试时,我最终得到了以下结果:
function generateError(){
throw new Error("oops");
}
function do(option: "opt1" | "opt2"){
if(option === "opt1") return true;
if(option === "opt2 ) return false;
generateError();
}
let res = do("blah");
那么,res
的预期类型是什么?根据编译器,它是string | undefined
(这是有道理的,虽然我必须说我期待string
)。我想我没有看到有一个新类型只是为了表示永不返回的函数。我们真的需要这个概念吗?这只是一个编译器,有助于它有更好的流量分析?
从来没有信息不应该达到这个特定部分。例如,在此代码中
function do(): never {
while (true) {}
}
你有一个无限循环,我们不想迭代无限循环。就这样。
但一个真正的问题是它对我们有什么用?例如,在创建更高级的类型以指出它们不是什么时,它可能会有所帮助
例如,让我们声明我们自己的NonNullable类型:
type NonNullable<T> = T extends null | undefined ? never : T;
这里我们检查T是否为null或未定义。如果是,那么我们指出它永远不会发生。然后在使用此类型时:
let value: NonNullable<string>;
value = "Test";
value = null; // error
您可以使用never
确保您不会错过功能合同。
function forever(): never {
while (true) {
break; // Error because you can't leave the function.
}
}
enum Values {
A,
B
}
function choose(value: Values) {
switch (value) {
case Values.A: return "A";
}
let x: never = value; // Error because B is not a case in switch.
}
永远(永远)返回的函数和可能抛出的函数并不完全相同。
例如:
function foo(option: "opt1" | "opt2"): string | undefined {
if (option === "opt1") return true;
if (option === "opt2") return false;
throw new Error("unknown option");
}
function bar(option: "opt1" | "opt2"): never {
while (true) {
doOption(option);
}
}
第一个可能(或可能不)返回,但它可以,所以返回类型不能是never
。如果它可以返回一个值,那么返回类型显然不是never
。
第二个永远不会回来。不是价值,不是未定义,没有。它不会返回,所以类型可以是never
。
有些函数看起来像#2但实际上属于#1,通常是在涉及throw
或者你在节点中使用process.exit
时(因为它杀死了进程而无法返回)。