Typescript似乎严格根据字段的私有变量来推断字段类型。 但是,它不会抱怨getter是否返回类型并集(1),也不会从getter(2)推断实际类型:
test('field type inference', () => {
class A {
x_: number;
// 1: no type checking here
get x(): number | undefined {
if (this.x_ === 1) return undefined;
return this.x_;
}
set x(v: number | undefined ) {
this.x_ = +v;
}
}
const a = new A();
a.x = 1;
// 2: The inferred type is number (as of x_, instead of getter)
const x: number = a.x;
console.log(a.x) // outputs 'undefined'
})
这是指定/预期的行为吗?
稍后编辑。请注意,strictNullCheck
也不会捕获此错误。仅有的两个将缺少初始化和设置器
下面的示例修复了strictNullCheck
条警告:
test('field type inference', () => {
class A {
x_: number;
get x(): number | undefined {
if (this.x_ === 1) return undefined;
return this.x_;
}
set x(v: number | undefined ) {
this.x_ = +(v ?? 0);
}
constructor(value: number) {
this.x_ = value;
}
}
const a = new A(2);
a.x = 1;
const x: number = a.x;
console.log(a.x)
});
答案 0 :(得分:2)
首先,当您拥有属性时,打字稿假定从属性中读取将检索最后写入该属性的值。您在这里的设置者违反了约定。但是,由于每个get / set函数从技术上来说都是类型安全的,因此typescript不会发现任何错误。
第二,当您为类型为联合的属性分配常量时,打字稿会记住该联合的哪个成员适用于该范围的其余部分。您在这些获取器/设置器中有逻辑的事实并不重要。
与私有财产无关,与公共财产无关。
假设您有一个非常简单的课程:
// No getters/setters
class B {
x: number | undefined
}
const b = new B()
b.x // number | undefined
b.x = 1
b.x // number
如您所见,打字稿会记住您分配的内容,知道它不是未定义的,然后将其从属性的结果类型中剥离出来,只要它知道它是正确的。
现在让我们尝试一下此类:
// useless getters/setters
class C {
get x(): number | undefined {
return undefined;
}
set x(v: number | undefined ) {
// no-op
}
}
const c = new C()
c.x // number | undefined
c.x = 1
c.x // number
现在,getters / setter方法没有用,但是却给您“错误”的结果。
如果在同一同步执行的范围内设置了最后一个值,Typescript期望getter返回最后一个设置值。实际上,大多数程序员也可能会这样做。
理想情况下,编译器会在此处标记出问题,但是要通过这些设置器来跟踪类型安全实际上是一件非常复杂的事情。