TypeScript 对象定义中的 '!:' 和 '?:' 有啥区别?
Posted
技术标签:
【中文标题】TypeScript 对象定义中的 \'!:\' 和 \'?:\' 有啥区别?【英文标题】:What is the difference Between '!:' and '?:' in TypeScript object definitions?TypeScript 对象定义中的 '!:' 和 '?:' 有什么区别? 【发布时间】:2020-12-10 19:54:10 【问题描述】:Class Employee
firstName: string;
lastName!: string;
middleName?: string;
Employee
类的这3个不同字段有什么区别?
Live Example
【问题讨论】:
typescriptlang.org/docs/handbook/…, typescriptlang.org/docs/handbook/release-notes/… 为什么不将完整的代码 放入 问题中(并在您处理问题时修复Class
/class
问题)?为什么只在场外?
这能回答你的问题吗? Type ORM '?' meaning in entities
【参考方案1】:
它们很好地隐藏在documentation of TypeScript中。
?
在interfaces 上进行了描述,它标志着optional property。
!
是definite assertion operator。它告诉编译器该属性已设置(不是 null
或 undefined
),即使 TypeScript 的分析无法检测到。
顺便说一句,Class
不是 TypeScript 或 javascript 关键字,会在该位置产生错误。他们声明类的关键字是class
。 TypeScript 和 JavaScript 标识符和关键字区分大小写(Class
和 class
是不同的东西)。
【讨论】:
【参考方案2】:?
在那个位置marks the property optional。
该位置的!
是definite assignment assertion。它是non-null assertion operator 的声明级版本,但用于属性(也可用于变量)而不是表达式。
该示例中有两个(或者可以说是三个)错误:
Class
应该是class
; JavaScript 和 TypeScript 区分大小写。
您需要firstName
上的初始化程序(或无条件分配给它的构造函数)。
lastName
上的 !
告诉 TypeScript,lastName
肯定会被分配,从而抑制了您为 firstName
获得的那种错误,但实际上(在示例中)没有任何效果 em> 使用 !
的任务承诺你肯定知道你正在做的 TypeScript。
编辑:code you linked 稍后处理上面的#1 和#2,但不处理#3。 TypeScript 不会警告 lastName
从未被赋值并假定它的值是一个字符串,而实际上它不存在,因此读取它的值将导致 undefined
。
【讨论】:
lastName!: string;
和declare lastName: string;
有什么区别?
@T.J.Crowder you can use declare
inside a class 截至 TS3.7 to support class field [[Define]] semantics。
@jcalz - 谢谢!【参考方案3】:
当有编译器选项strictNullChecks: false
如果您的tsconfig.json
中有strictNullChecks: false
,那么它们完全相同,因为禁用strictNullChecks
意味着所有字段都可以将空值或未定义为有效值。
当有编译器选项strictNullChecks: true
class Employee
firstName: string;
lastName!: string;
middleName?: string;
firstName: string
表示firstName
必须是string
。 null
或 undefined
不是 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
是唯一允许的类型。不允许使用 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';
在前面的代码中,lastName
肯定是通过this.init()
调用在constructor
中分配的。但是,编译器无法知道这一点。所以添加!基本上是在告诉编译器“闭嘴,我知道我在做什么”。然后由您来确保代码的正确性。
关于middleName?: string
语法。这类似于middleName: string | undefined
;由于所有值都有一个默认值undefined
,因此编译器不会抱怨middleName
没有被赋值。
【讨论】:
以上是关于TypeScript 对象定义中的 '!:' 和 '?:' 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
将自定义道具传递给 TypeScript 中的 Redux 表单字段
在 Vue 3 Typescript 中使用提供/注入访问组件中的方法,错误对象可能是“未定义”