TypeScript 对象定义中的 '!:' 和 '?:' 有什么区别?

kar*_*ini 6 class optional typescript

Class Employee {
  firstName: string;
  lastName!: string;
  middleName?: string;
}
Run Code Online (Sandbox Code Playgroud)

这3个不同领域的Employee课程有什么区别?

现场示例

She*_*iny 31

当有编译器选项时strictNullChecks: false

如果您有strictNullChecks: falsetsconfig.json那么它们完全相同,因为strictNullChecks禁用意味着所有字段都可以将 null 或 undefined 作为有效值。

当有编译器选项时strictNullChecks: true

class Employee {
   firstName: string;
   lastName!: string;
   middleName?: string;
}
Run Code Online (Sandbox Code Playgroud)

firstName: string意味着这firstName必须是一个string. nullundefined不是名字的有效值。

所有未初始化的字段都将具有默认值undefined,因此这将导致错误Property 'firstName' has no initializer and is not definitely assigned in constructor

要消除错误,您需要更改声明firstName: string = 'Some default value'或添加构造函数并在构造函数中为其分配值。

constructor() {
    this.firstName = 'some default value';
}
Run Code Online (Sandbox Code Playgroud)

现在为!句法。语法lastName!: string类似于lastName: string它基本上表示这string是唯一允许的类型。null并且undefined不被允许。但它会让编译器对明确的赋值错误保持沉默。假设您有以下代码。

   class Employee {
       firstName: string;
       lastName!: string;
       middleName?: string;

      constructor() {
          // This will silence the compiler about first name not initialized
          this.firstName = 'some default value';
          // The compiler cannot tell that lastName is assigned in init() function
          this.init();
      }
      
      private init(): void {
          this.lastName = 'some default value';
      }
    }
Run Code Online (Sandbox Code Playgroud)

在前面的代码中,lastName肯定是在 constructor viathis.init()调用中赋值的。然而,编译器无法知道这一点。所以添加 ! 基本上是告诉编译器“闭嘴,我知道我在做什么”。然后由您来确保代码的正确性。

关于middleName?: string语法。这类似于middleName: string | undefined;由于所有值都有默认值undefined,因此编译器不会抱怨middleName未分配。


T.J*_*der 6

?在那个位置标记属性可选

!在那个位置是明确赋值断言。它是非空断言运算符的声明级版本,但用于属性(也可以用于变量)而不是表达式。

在这个例子中有两个——或者可以说是三个——错误:

  1. Class应该是class;JavaScript 和 TypeScript 区分大小写。

  2. 您需要一个初始化程序firstName(或一个无条件分配给它的构造函数)。

  3. !lastName告诉打字稿那lastName肯定会被分配,抑制那种你得到错误的firstName,但没有(在本例中)实际上的是使用赋值!有承诺打字稿你肯定知道你在干什么。

编辑:稍后链接代码处理上面的#1 和#2,但不处理#3。TypeScript 不会警告lastName从未赋值并假定它的值是一个字符串,而实际上它不存在,因此读取它的值将导致undefined.


axi*_*iac 5

它们很好地隐藏在TypeScript 文档中。

?是在接口上描述的,它标记了一个可选属性

!定断言运算符。它告诉编译器该属性已设置(不是nullundefined),即使 TypeScript 的分析无法检测到这一点。


顺便说一句,Class不是 TypeScript 或 JavaScript 关键字,并且会在该位置产生错误。他们声明类的关键字是class。TypeScript 和 JavaScript 标识符和关键字区分大小写(Class并且class是不同的东西)。