我有三种类型
type TypeA = {
name: "A",
prop1: string,
}
type TypeB = {
name: "B",
prop2: string,
}
type Default = {
name: string,
}
type AllTypes = TypeA | TypeB | Default
现在,我有一个已批准的密钥的联合,可用于构造对象类型。
type Approved = "A" | "B" | "C" | "D"
我想要一个如下所示的类型:
type Result = {
A?: TypeA,
B?: TypeB,
C?: Default,
D?: Default,
}
这可能吗?我尝试了类似的方法,但它没有按预期工作
type FromUnion<T extends AllTypes, K extends Approved> = {
[K in Approved]?: Extract<T, {name: K}>
}
FromUnion<AllTypes, "A"> // gives me the `AllTypes` type.
一种方法如下:
type Result = { [K in Approved]?:
OrDefault<Extract<AllTypes, { name: K }>, Default>
}
type OrDefault<T, D> = [T] extends [never] ? D : T;
这是一个映射类型,其中键
K
迭代Approved
的成员。这与您正在做的类似,我们 Extract
AllTypes
的成员,其 name
属性的类型为 K
。这将为您提供 TypeA
代表 A
和 TypeB
代表 B
。但对于 C
和 D
这给出了 never
因为 AllTypes
没有这样的成员。
这就是
OrDefault<T, D>
的用武之地。这是一个实用程序类型,用于检查 T
是否为 never
。如果是,则返回 D
。否则返回 T
。它通过条件类型(我们将检查包装在[
⋯]
中以避免在T
上进行分布,请参阅为什么我们在条件中使用方括号`[]`?)
我们写成
Extract<AllTypes, { name: K }>
,而不是 OrDefault<Extract<AllTypes, { name: K }>, Default>
,这给了我们
/* type Result = {
A?: TypeA;
B?: TypeB;
C?: Default;
D?: Default;
} */
随心所欲。