我有三种类型

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,
}

这可能吗?我try 过这样的东西,但效果不佳

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;

这是一个mapped type,其中键KApproved的成员上迭代.这与您正在做的事情类似,其中我们Extract AllTypes的成员,其name属性是K类型. 这为A提供TypeA,为B提供TypeB. 但对于CD,这给出了never,因为AllTypes中不存在这样的成员.

这就是OrDefault<T, D>的用武之地. 这是一个实用程序类型,判断T是否是never.如果是,则返回D.否则返回T. 它通过conditional type来实现这一点(我们将支票包裹在[ ]中,以避免distributing超过T,参见Why do we use square brackets `[]` in conditionals?)

我们写OrDefault<Extract<AllTypes, { name: K }>, Default>而不是Extract<AllTypes, { name: K }>,这给了我们

/* type Result = {
    A?: TypeA;
    B?: TypeB;
    C?: Default;
    D?: Default;
} */

如所需.

Playground link to code

Typescript相关问答推荐

接口的额外属性作为同一接口的方法的参数类型'

向NextAuth会话添加除名称、图像和ID之外的更多详细信息

打印脚本中的动态函数重载

为什么我的一个合成函数不能推断类型?

TypeScrip省略了类型参数,仅当传递另一个前面的类型参数时才采用默认类型

如何创建一家Reduxstore ?

为什么在leetcode问题的测试用例中,即使我确实得到了比预期更好的解决方案,这段代码也失败了?

为什么我的查询钩子返回的结果与浏览器的网络选项卡中看到的结果不同?

打字脚本中的模块化或命名空间

在Reaction中折叠手风琴

如何从接口中省略接口

react 路由不响应参数

将类型脚本函数返回类型提取到VSCode中的接口

有没有办法在Reaction组件中动态导入打字脚本`type`?

有没有一种更好的方法来存储内存中的数据,而不是在类型脚本中使用数组和基于索引的函数?

基于属性值的条件类型

使用本机 Promise 覆盖 WinJS Promise 作为 Chrome 扩展内容脚本?

剧作家测试未加载本地网址

是否可以使用元组中对象的键来映射类型

为什么我的 Typescript 函数中缺少 void 隐式返回类型?