英文:
How can I tell typescript that an object's function will populate an otherwise null property?
问题 {#heading}
我的问题与这个类似:
Type Name = {firstName: string, lastName: string}
class NameClass {
public _name: Name | null;
constructor() {
this._name = null;
}
// 或任何函数
public set name(name: Name) {
this._name = name;
}
public printName() {
if (!this._name) this.name = { firstName: "should not", lastName: "be null" };
// v 即使我刚刚设置了,对象可能为空 ^
console.log(this._name.firstName);
}
}
我知道可以简单地使用 "!" 断言来解决这个问题,或者可以创建一个单独的函数来确保对象不为空,但我正在寻找一种告诉 TypeScript 函数将设置属性的方法。
在问题中提出了一个解决方案,但我认为这种方法有点巧妙,而且并没有真正解决问题。这个帖子也是4年前的了,所以我希望有更好的方法来解决这个问题。 英文:
My problem is similar to this:
Type Name = {firstName: string, lastName: string}
class NameClass {
public _name: Name \| null;
constructor() {
this._name = null;
}
// or any function
public set name(name: Name) {
this._name = name;
}
`public printName() {
if (!this._name) this.name = { firstName: "should not", lastName: "be null" };
// v Object may be null even though I just set it ^
console.log(this._name.firstName);
}
}
`
I'm aware I can simply use the " ! " assertion to get around this or can create a separate function to make sure that the object is not null, but I'm looking for a way to tell typescript that the function will set the property.
There is a solution proposed in question
but I find this kind of hacky and doesn't really solve the problem. The post was also 4 years ago, so I'm hoping there is a better way to fix this?
答案1 {#1}
得分: 1
你考虑过在构造函数中初始化 _name 属性吗?
type Name = {firstName: string, lastName: string}
class NameClass {
public _name: Name;
constructor() {
this._name = { firstName: "不应该", lastName: "为 null" };
}
// 或者任何函数
public set name(name: Name) {
this._name = name;
}
public printName() {
console.log(this._name.firstName);
}
}
TypeScript 允许这样做,因为这样 _name 总是被设置。 英文:
Have you considered initializing the _name property in the constructor?
type Name = {firstName: string, lastName: string}
class NameClass {
public _name: Name;
constructor() {
this._name = { firstName: "should not", lastName: "be null" };
}
// or any function
public set name(name: Name) {
this._name = name;
}
public printName() {
console.log(this._name.firstName);
}
}
Typescript is okay with that, because that way _name is always set.
答案2 {#2}
得分: 0
如果我没有错,问题并不是告诉 TypeScript "如何做" - 这根本不可能。这个类不能也永远不会知道,在哪个函数中(或其他方式)设置了可空属性是什么。拥有可空属性的整个目的就是有机会将该属性设置为 null。即使在设置属性后,它也可能返回到 null(例如通过另一个函数)。
一个解决方法是在构造函数中将该属性设置为默认字符串值("")。
另外作为一点注意,不建议使用下划线开头的公共属性。通常,只有private
字段会这样命名。
英文:
If im not mistaken, the problem is not telling typescript "how to do it" - it is simply not possible. The class cannot and will never know, what nullable property was set in what function (or some other way). The whole point of having a nullable property is to have the opportunity to set that property to null. Even after setting the property, it may return back to null (e. g. through another function).
A work around would be having that property set to defalt string values (""
) in the constructor.
Also as a side-note, it is not recommendet to have a public property start with an underscore. Normally, only private
fields are named like that.
答案3 {#3}
得分: 0
这个版本进行类型检查:
type Name = { firstName: string; lastName: string };
class NameClass {
public _name: Name | null;
constructor() {
this._name = null;
}
ensureName(): asserts this is { _name: Name } {
if (!this._name)
this.name = { firstName: 'should not', lastName: 'be null' };
}
// 或者任何函数
public set name(name: Name) {
this._name = name;
}
public printName() {
this.ensureName();
console.log(this._name.firstName);
}
}
但我认为使用非空断言运算符更符合习惯,并且在大多数情况下,TypeScript 相信您使用 asserts ...
语法时提供足够的保证。
英文:
This version type checks:
type Name = { firstName: string; lastName: string };
class NameClass {
public _name: Name | null;
constructor() {
this._name = null;
}
ensureName(): asserts this is { _name: Name } {
if (!this._name)
this.name = { firstName: 'should not', lastName: 'be null' };
}
// or any function
public set name(name: Name) {
this._name = name;
}
public printName() {
this.ensureName();
console.log(this._name.firstName);
}
}
but I think using the non-null assertion operator is more idiomatic, and doesn't give you less guarantees, as TS mostly trusts you regarding the asserts ...
syntax.