众所周知,您可以在查询后使用标记的联合类型来获得正确的类型:
export interface A {
type: 'a'
foo: string
}
export interface B {
type: 'b'
bar: string
}
export type U = A | B
const a: U = {}
switch (a.type) {
case 'a':
// is now A
console.log(a.foo) // .foo is a string
break
}
但是,在动态查找时,我无法找到动态获取正确类型的解决方案:
export interface A {
type: 'a'
foo: string
}
export interface B {
type: 'b'
bar: string
}
export type U = A | B
class Foo {
private items: U[]
public get(name: U['type']) {
return this.items.find((i) => i.type === name)
}
}
const foo = new Foo()
const a = foo.get('a')
a // a is U but should be A
似乎打字稿不能自动找出类型。
我也尝试过使用泛型类型,我希望打字稿可以猜到,就像那样:
public get<T extends U>(name: T['type']): T {
return this.items.find((i) => i.type === name)
}
我希望T是由T ['type']选择的界面,但它有相同的结果。
答案 0 :(得分:1)
不幸的是,打字稿不会像你描述的那样进行“向后”推理(例如,我们不能自动从某种类型的字段转到那种类型)。相反,一种解决方案是明确描述您的关系。然后很容易得到你正在寻找的行为:
type UMap = {
"a": A;
"b": B;
}
class Foo {
private items: U[]
public get<K extends keyof UMap>(name: K): UMap[K] {
return this.items.find((i) => i.type === name)
}
}
const a = foo.get('a') // a has type A
const b = foo.get('b') // b has type B
我还建议从地图生成类型U
,而不是明确声明:
type U = UMap[keyof UMap]; // A | B
这样,您可以在向联合添加更多类型时,只需要在一个位置更新内容。