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

nhn9ugyo  于 2023-01-27  发布在  TypeScript
关注(0)|答案(4)|浏览(222)
Class Employee {
  firstName: string;
  lastName!: string;
  middleName?: string;
}

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

dw1jzc5e

dw1jzc5e1#

具有编译器选项strictNullChecks: false

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

具有编译器选项strictNullChecks: true

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

firstName: string表示firstName必须是stringnullundefined不是名字的有效值。
所有未初始化的字段都将具有默认值undefined,因此这将导致错误Property 'firstName' has no initializer and is not definitely assigned in constructor
要消 debugging 误,您需要将声明更改为firstName: string = 'Some default value',或者添加一个构造函数并在构造函数中为它赋值。

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

现在来看看!语法。lastName!: string语法与lastName: string类似,基本上是说string是唯一允许的类型。nullundefined是不允许的。但是它会让编译器对明确的赋值错误保持沉默。假设您有以下代码。

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

在前面的代码中,lastName通过this.init()调用在constructor中被明确赋值,但是编译器不知道这一点,所以添加!基本上就是告诉编译器 “闭嘴,我知道我在做什么”,然后由您来确保代码的正确性。
关于middleName?: string语法。这与middleName: string | undefined类似;因为所有的值都有一个默认值undefined,所以编译器不会抱怨middleName没有赋值。

1l5u6lss

1l5u6lss2#

该位置的?将属性标记为可选。
这个位置的!是明确赋值Assert,它是非空Assert操作符的声明级版本,但用于属性(也可以用于变量)而不是表达式。
在这个例子中有两个--或者可以说是三个--错误:

  1. Class应为class;JavaScript和TypeScript区分大小写。
    1.在firstName上需要一个初始化器(或者一个无条件赋值给它的构造函数)。
  2. lastName上的!告诉TypeScript,lastName肯定会被赋值,从而抑制了您在firstName上遇到的那种错误,但(在示例中)没有任何东西实际上 * 执行 * 赋值,即使用!可以保证TypeScript您确信您正在执行赋值。
  • 编辑:code you linked稍后处理上面的#1和#2,但不处理#3。TypeScript不会警告lastName从未被赋值,并假设它的值是一个字符串,而事实上它并不存在,因此阅读它的值将导致undefined。*
8tntrjer

8tntrjer3#

它们很好地隐藏在documentation of TypeScript中。
?interfaces上描述,它标记了一个可选属性。
!是明确Assert运算符。它告诉编译器属性已设置(不是nullundefined),即使TypeScript的分析无法检测到。
顺便说一句,Class不是TypeScript或JavaScript关键字,在那个位置会产生错误。声明类的关键字是class。TypeScript和JavaScript标识符和关键字区分大小写(Classclass是不同的东西)。

5q4ezhmt

5q4ezhmt4#

在TypeScript中,**!?**字符用于指示对象类型定义中的可选属性和不可为空的属性。

**!**字符用于指示不可为空的属性,这意味着该属性是必需的并且必须具有值。例如:

interface Person {
  name!: string;
  age!: number;
}

const person: Person = { name: "John", age: 30 };

**?**字符用于指示可选属性,表示该属性不是必需的,可以不定义。例如:

interface Person {
  name?: string;
  age?: number;
}

const person: Person = { name: "John" };

在本例中,age属性是可选的,不需要定义。
需要注意的是,当您在接口中使用**!时,它意味着变量是必需的,您不能将nullundefined赋给它,但如果您使用?**,则变量不是必需的,但您仍然可以将nullundefined赋给它。

相关问题