我有一个值,该值可以是A型或B型,并且显式地是A:
let valueOptional: A|B;
let valueExplicit: A;
现在我进行类型检查,然后设置值:
if ((typeof valueOptional).toString() === 'B') {
valueExplicit = convertB2A(valueOptional);
} else {
valueExplicit = valueOptional;
}
现在,编译器仍然会抛出此错误:
Type 'A | B' is not assignable to type 'A'.
Type 'A' is not assignable to type 'B'.
Property 'xyz' is missing in type 'B'.
有没有办法解决这个问题?
答案 0 :(得分:3)
如果您有一个联合,并且想要将联合的类型缩小为它的组成部分之一,则需要使用类型保护。编译器理解为类型保护的内容是有限的,我们可以在给定类型上使用的内容还取决于我们拥有的类型。
对于基元,我们可以使用typeof
类型防护:
let valueOptional: number|string;
let valueExplicit: number;
if (typeof valueOptional === 'number') {
valueExplicit = valueOptional; // valueOptional is number here
} else {
valueExplicit = +valueOptional //valueOptional is string and we convert
}
对于类,我们可以使用instanceof
类型防护:
class A { constructor(public foo: number) { } }
class B { constructor(public bar: number) { } }
let valueOptional: A | B;
let valueExplicit: A;
if (valueOptional instanceof A) {
valueExplicit = valueOptional; // valueOptional is A here
} else {
valueExplicit = new A(valueOptional.bar) //valueOptional is B and we convert
}
如果A
和B
是接口,我们可以使用in
类型防护根据属性的存在来确定类型(typeof
或{{1 }}将起作用,因为在运行时实际上并没有以任何方式表示接口)。 instanceof
类型防护可以与类一起使用,但是对于接口,它是唯一的选择:
in
如果条件更复杂,也可以使用自定义类型防护:
interface A { foo: number }
interface B { bar: number }
let valueOptional: A | B;
let valueExplicit: A;
if ('foo' in valueOptional) {
valueExplicit = valueOptional; // valueOptional is A here
} else {
valueExplicit = { foo: valueOptional.bar } //valueOptional is B and we convert
}
您还可以混合使用类型保护符:
interface A { foo: number }
interface B { foo: string }
let valueOptional: A | B;
let valueExplicit: A;
// any condition that returns true/false will do, used an arrow function but any function that returns param is type will act as a type guard.
const isA = <T>(v: T | A): v is A => typeof (v as A).foo === 'number';
if (isA(valueOptional)) {
valueExplicit = valueOptional; // valueOptional is A here
} else {
valueExplicit = { foo: +valueOptional.foo } //valueOptional is B and we convert
}