如何从具有给定键列表的对象类型的联合构造类型

问题描述 投票:0回答:1

我有三种类型

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.
typescript
1个回答
0
投票

一种方法如下:

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;
} */

随心所欲。

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.