之间的区别!和'?'在TypeScript中

问题描述

Class Employee {
  firstName: string;
  lastName!: string;
  middleName?: string;
}

Employee类的这3个不同字段中有什么区别?

Live Example

解决方法

位于marks the property optional位置的?

该位置的!definite assignment assertion。它是non-null assertion operator的声明级版本,但用于属性(也可以用于变量)而不是表达式。

在此示例中有两个错误,或者可以说是三个错误:

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

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

  3. !上的lastName告诉TypeScript肯定会分配lastName,从而抑制了您为firstName遇到的那种错误,但是没有(在示例中)实际上的分配是使用!保证您知道自己正在执行TypeScript。

编辑:code you linked随后处理上述#1和#2,但不适用于#3。 TypeScript不会警告lastName从未分配,并假定其值为字符串,而实际上它不存在,因此读取其值将导致undefined

,

它们很好地隐藏在documentation of TypeScript中。

?interfaces上进行了描述,它标记为optional property

!definite assertion operator。它告诉编译器即使TypeScript的分析无法检测到该属性,也已设置了该属性(不是nullundefined)。


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

,

具有编译器选项strictNullChecks: false

如果您的strictNullChecks: false中有tsconfig.json,则它们是完全相同的,因为禁用strictNullChecks意味着所有字段为空或未定义为有效值。

具有编译器选项strictNullChecks: true

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

firstName: string表示firstName必须是stringnullundefined对于firstName无效。

所有字段的默认值为undefined,这将导致错误Property 'firstName' has no initializer and is not definitely assigned in constructor

要使错误静音,您需要将声明更改为firstName: string = 'Some default value'或添加一个构造函数并在构造函数中为其指定一个值。

constructor() {
    this.firstName = 'some default value';
}

现在开始!句法。 lastName!: string的语法与lastName: string相似,因为它基本上说只有string是唯一允许的类型。不允许使用nullundefined。但是它将使编译器无法确定分配错误。假设您有以下代码。

类员工{ firstName:字符串; lastName !:字符串; middleName ?:字符串;

  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';
  }
}

在先前的代码中,lastName肯定是通过constructor调用在this.init()中分配的。但是编译器不知道这一点。所以加了!基本上是告诉编译器“闭嘴,我知道我在做什么” 。然后由您来确保代码的正确性。

关于middleName?: string语法。这与middleName: string | undefined完全相同;由于所有值的默认值均为undefined,因此编译器不会抱怨未分配middleName

,

这3个不同的Employee类字段有什么区别?

Employee实例执行以下操作:

  • 需要具有名字,但它的值可以是字符串或null / undefined
  • 需要具有lastName,并且其值不能为null / undefined。它必须是一个字符串。
  • 可选地包含字符串的MiddleName或null / undefined