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

在Typescript中,什么是!取消引用成员时的(感叹号/bang)运算符?,typescript,tslint,Typescript,Tslint,在查看tslint规则的源代码时,我遇到了以下语句: if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) { return; } 注意节点后的运算符。父项。有趣 我首先尝试使用当前安装的TS版本(1.5.3)在本地编译该文件。由此产生的错误指向爆炸的确切位置: $ tsc --noImplicitAny memberAccessRule.ts noPublicModifierRule.ts(57,24):

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

if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    return;
}
注意
节点后的运算符。父项
。有趣

我首先尝试使用当前安装的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
未定义的
,所以不要抱怨它可能是
null
未定义的
”的方法。有时,类型检查器本身无法进行确定

解释如下:

一个新的
修复后表达式运算符可用于在类型检查器无法得出结论的上下文中断言其操作数为非null和非未定义。具体来说,操作
x
生成一个
x
类型的值,其中
null
undefined
被排除在外。与形式为
x
x as T
的类型断言类似,
非空断言运算符在发出的JavaScript代码中被简单删除


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

Louis的回答很好,但我想我会尝试简单地总结一下:

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

非null断言运算符 使用非空断言运算符,我们可以明确地告诉编译器表达式的值不是
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代码

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

“严格使用”;
函数simpleExample(nullableArg){
常量normal=nullableArg;
常量运算符applied=nullableArg;

}
很好的解释。我发现在附加
之前对相关变量执行
控制台.assert()
是一个很好的做法在它之后。因为添加
告诉编译器忽略空检查,它在javascript中编译为noop。因此,如果您不确定该变量是否为非空,那么最好执行显式断言检查。作为一个激励性的示例:使用新的ES映射类型,代码类似于
dict.has(key)?dict.get(键):“默认值”TS编译器无法推断
get
调用从不返回null/undefined<代码>dict.has(键)?得到(钥匙)!:'违约",正确地缩小了类型。这个操作符是否有俚语,比如Elvis操作符是如何引用二进制操作符的?@Jayesh你能在控制台上展开吗。assert()好的做法,你能举个例子吗?@ebakunin“bang操作符”,正如你在Mike的回答中看到的,作为编译器,它已经搞糟了。如果构造函数没有初始化属性,但是生命周期钩子初始化了属性,而编译器没有识别它。这不是TS编译器的责任。与其他一些语言(如C#)不同,JS(因此TS)不要求在使用前初始化变量。或者,从另一个角度来看,在JS中,用
var
let
声明的所有变量都隐式初始化为
undefined
。此外,类实例属性可以这样声明,因此
class C{constructor(){this.myVar=undefined;}}
是完全合法的。最后,生命周期挂钩依赖于框架;例如,Angular和React以不同的方式执行它们。因此TS编译器不能对此进行推理。考虑到TS中基于控制流的类型分析的可靠性,bang运算符是否有一个有效的用例?@Eugenekaratev readability。感叹号告诉代码的读者:它不能为空。(关于上限的事,我很抱歉)。而
表示:这可能是
null
,这是不正确的(因此,如果您绝对知道它不是
null
@EugeneKarataev,您只能使用
),区别在于
?。
返回类型是可以为null的(即使它永远不会发生),您将不得不处理一个可为null的类型。如果您知道null是不可能的,
!。
一劳永逸地修复了该类型。非常感谢您指出@Emile Bergeron您完全正确!我用一个更好的示例更新了答案。