我有一个代码,如:
// Those two come from backend, it cannot be guaranted
// they do not contain additional fields of any type.
interface Foo1 {
name: string;
}
interface Foo2 {
description: string;
}
// This one is mine and should always contain valid types
class Bar {
text: string;
constructor(data: Foo1 | Foo2 | Bar) {
this.text = data.name || data.description || data.text;
// Some more similar rules and throwing exceptions
// if types are incorrect
}
}
问题是 TypeScript 抱怨name
不存在Bar
和text
不存在Foo
等等,尽管事实上无论data
它们中的一个的类型肯定存在,this.text
总是设置为正确的类型。
如何在此处指定打字稿类型以避免此类问题但仍接受构造函数中的两种类型?
附:我不是在问instanceof
,它不适用于接口。我问的是正确注释类型,而且仅此而已。改变代码的逻辑不是我问题的答案。
缩小联合的方法始终是类型保护。您永远无法访问联合的不常见属性。
使用类型保护,您可以将代码重写为:
class Bar {
text: string;
constructor(data: Foo1 | Foo2 | Bar) {
this.text = 'description' in data ? data.description:
'name' in data ? data.name :
data.text;
}
}
您可以创建一个自定义类型,强制所有联合成分具有所有属性,但定义为undefined
. 这将允许访问公共属性:
interface Foo1 {
name: string;
}
interface Foo2 {
description: string;
}
type KeyOfUnion<T> = T extends T ? keyof T : never;
type ExpandUnionHelper<T, K extends PropertyKey> = T extends T ? T & Partial<Record<Exclude<K, keyof T>, undefined>> : never
type ExpandUnion<T> = ExpandUnionHelper<T, KeyOfUnion<T>>
// This one is mine and should always contain valid types
class Bar {
text: string | undefined;
constructor(data: ExpandUnion<Foo1 | Foo2 | Bar>) {
this.text = data.text || data.name || data.description
}
}
但这不会是一个确切的结果,因为它被输入为 string | undefined
最简单的解决方案可能是使用类型断言,虽然不是很优雅,但在这种情况下应该没问题。
// This one is mine and should always contain valid types
class Bar {
text: string;
constructor(data: Foo1 | Foo2 | Bar) {
this.text = (data as Foo1).name || (data as Foo2).description || (data as Bar).text;
// Some more similar rules and throwing exceptions
// if types are incorrect
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句