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

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

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

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

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

接下来我升级到最新的TS(2.1.6),编译它没有问题。所以这似乎是TS 2.x的特色。但是在编译过程中完全忽略了爆炸声,导致了下面的JS:

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

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

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


当前回答

非空断言运算符

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

例子

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不知道非空断言运算符的概念,因为这是TS的一个特性

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

其他回答

路易斯的回答很好,但我想我应该试着简单总结一下:

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

非空断言运算符

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

例子

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不知道非空断言运算符的概念,因为这是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 SampleType
let 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 | null
let s1 = ns!
//  ^? let s1: string
let s2 = ns as NonNullable<typeof ns>
//  ^? let s2: string

这是非空断言操作符。它是一种告诉编译器“这个表达式在这里不能为空或未定义,所以不要抱怨它为空或未定义的可能性。”有时类型检查器本身无法做出这种判断。

在TypeScript发布说明中有解释:

一个新的!后修正表达式运算符可用于断言其操作数非空且非未定义,这种情况下类型检查器无法得出这一事实。具体来说,就是运算x!生成一个x类型的值,其中排除了null和undefined。类似于<T>x和x作为T的形式的类型断言,!在发出的JavaScript代码中删除非空断言运算符。

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