当你写这个时:
class Optional {
id?: number;
}
您已声明id 是optional property。这意味着它可能存在也可能不存在于Optional 的实例中。如果存在,则该值应该是number(或者可能是undefined,除非您使用的是the --exactOptionalPropertyTypes compiler option)。如果它不存在,那么如果您读取id 属性,则该值将是undefined。
以上解决了编译器警告,因为您不需要初始化可选属性;当你读到它时,它就是undefined。
无论如何,这意味着您不能只将id 属性用作number:
const o = new Optional();
o.id.toFixed(2) // compiler error!
//~~ <-- Object is possibly undefined
这个警告很好,对吧?因为不想误读undefined的toFixed()方法。您需要先检查 undefined,可能使用optional chaining operator (?.):
o.id?.toFixed(2) // okay
当您不确定属性是否会在用户想要访问它们的时间分配,并且您希望保护这些用户免受潜在的运行时错误时,可选属性是一种合理的方法。
另一方面,当你写这个时:
class Asserted {
id!: number
}
您已断言id 属性has definitely been assigned。这个断言是你告诉编译器一些它不能自己验证的东西。这在您实际分配属性但编译器无法遵循逻辑的情况下很有用:
class ActuallyAssigned {
id!: number
constructor() {
Object.assign(this, { id: 123 });
}
}
ActuallyAssigned 的实例将在构造函数中设置id 属性,因为the Object.assign() function 将属性从所有后续参数复制到第一个参数中。但是编译器无法理解这一点,因此如果没有明确的赋值断言,您会收到警告。在这里消除该警告是合理的。
但在上面的Asserted 中,这是不合理的。你对编译器撒了谎。它看不到id 已分配,因为它实际上未 已分配。因此,如果您继续将id 属性视为number,即使它可能是undefined,您也不会收到编译器警告:
a.id.toFixed(2) // no compiler error, but
// ? RUNTIME ERROR: o.id is undefined
因此,当用户想要访问属性很可能是undefined 时,不建议使用明确的赋值断言。
Playground link to code