在TypeScript中,当取消引用成员时,什么是!(感叹号/砰)运算符?

在查看tslint规则的源代码时,我遇到了以下语句:

if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) {return;}

注意node.parent后面的!运算符。有趣!

我首先尝试使用当前安装的TS(1.5.3)版本在本地编译文件。产生的错误指向爆炸的确切位置:

$ tsc --noImplicitAny memberAccessRule.tsnoPublicModifierRule.ts(57,24): error TS1005: ')' expected.

接下来我升级到最新的TS(2.1.6),它编译它没有问题。所以它似乎是TS 2. x的功能。但是转译完全忽略了爆炸,导致以下JS:

if (node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression) {return;}

到目前为止,我的谷歌FU让我失望了。

什么是TS的感叹号操作符,它是如何工作的?

441171 次浏览

这是非空断言运算符。它是一种告诉编译器“这个表达式在这里不能是nullundefined,所以不要抱怨它可能是nullundefined。”有时类型检查器本身无法做出决定。

解释这里

在类型检查器无法得出这一事实的上下文中,可以使用新的!修复后表达式运算符来断言其操作数是非null和非未定义的。具体来说,操作x!产生的值类型为x,排除了nullundefined。与表单<T>xx as T的类型断言类似,!非空断言运算符在发出的JavaScript代码中被简单地删除。

我发现在这个解释中使用术语“断言”有点误导。它是开发商正在断言它意义上的“断言”,而不是将要执行测试的意义。最后一行确实表明它不会导致发出JavaScript代码。

路易斯的回答很好,但我想我会试着简明扼要地总结一下:

Bang运算符告诉编译器暂时放松它可能要求的“不为空”约束。它对编译器说:“作为开发人员,我比你更清楚这个变量现在不能为空”。

非空断言运算符

使用非空断言运算符,我们可以显式地告诉编译器表达式的值不是nullundefined。当编译器无法确定地推断类型但我们拥有比编译器更多的信息时,这很有用。

示例

ts代码

function simpleExample(nullableArg: number | undefined | null) {const normal: number = nullableArg;//   Compile err://   Type 'number | null | undefined' is not assignable to type 'number'.//   Type 'undefined' is not assignable to type 'number'.(2322)
const operatorApplied: number = nullableArg!;// compiles fine because we tell compiler that null | undefined are excluded}

编译的JS代码

请注意,JS不知道Non-null断言运算符的概念,因为这是一个TS特性

"use strict";function simpleExample(nullableArg) {const normal = nullableArg;const operatorApplied = nullableArg;}

简短回答

非空断言运算符(!)可以帮助编译器确定此变量不是空变量或未定义变量。

let obj: { field: SampleType } | null | undefined;
... // some code
// the type of sampleVar is SampleTypelet sampleVar = obj!.field; // we tell compiler we are sure obj is not null & not undefined so the type of sampleVar is SampleType

我的理解是!操作符与NonNullable做同样的事情。

let ns: string | null = ''//  ^? let ns: string | nulllet s1 = ns!//  ^? let s1: stringlet s2 = ns as NonNullable<typeof ns>//  ^? let s2: string