typescript - 为什么 Typescript Union + 映射类型在使用和不使用泛型的情况下工作方式不同

标签 typescript typescript-typings typescript-generics

我刚开始使用泛型。下面的代码有不同的“w0”和“w1”,但代码看起来是一样的。

为什么它们不同,以及我如何以相反的方式获得相反的类型。

我查了一些文档,但没有找到任何解释,有没有文档可以解释它们不同类型的原理?

我怎样才能得到Calc<BaseA> | Calc<BaseB>没有CalcGenerics .

我怎样才能得到{ type: "A" | "B"; flag: number; }Generics .

type BaseA = {
  type: 'A'
  name: string
  flag: number
}

type BaseB = {
  type: 'B'
  id: number
  flag: number
}

type Base = BaseA | BaseB

type w0 = {
  [k in keyof Base]: Base[k]
}
/*
w0 = {
  type: "A" | "B";
  flag: number;
}
*/
type Calc<W> = {
  [k in keyof W]: W[k]
}
type w1 = Calc<Base>
/*
w1 = Calc<BaseA> | Calc<BaseB>
*/
type z0 = Exclude<w0,BaseA>
// z0 = w0
type z1 = Exclude<w1,BaseA>
// z1 = BaseB

最佳答案

第一个问题很容易解决:

type Q1 = {
  [B in Base as B["type"]]: {
    [K2 in keyof B]: B[K2]
  }
}[Base["type"]]

// type Q1 = {
//     type: 'A';
//     name: string;
//     flag: number;
// } | {
//     type: 'B';
//     id: number;
//     flag: number;
// }

我们首先映射Base中的每个元素,并将type键作为结果类型的键。对于每个元素,我们可以映射该元素的键。最后,我们使用 Base["type"] 索引该类型以获取并集。

您现在可以用 Calc 替换内部 map 。

type Q1 = {
  [B in Base as B["type"]]: Calc<B>
}[Base["type"]]

// type Q1 = Calc<BaseA> | Calc<BaseB>

第二个问题有点棘手。这是由 Distributive Conditional Types 引起的。我发现只能用这个技巧来禁用分配性:

type Calc2<W extends [any]> = {
  [k in keyof W[0]]: W[0][k] 
}

type Q2 = Calc2<[Base]>

// type Q2 = {
//     type: "A" | "B";
//     flag: number;
// }

Playground

关于typescript - 为什么 Typescript Union + 映射类型在使用和不使用泛型的情况下工作方式不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72810324/

相关文章:

typescript - 工作函数,即使它返回错误的类型

angular - 在模型类 Angular 中注入(inject)服务

typescript - 如何制作依赖于先前值的 typescript 定义?

typescript - 如何使用一个函数的返回类型作为另一个函数的参数类型?

typescript - 避免在 switch 中进行 typescript 转换

javascript - 检查数组中是否至少有两个元素大于零 - JavaScript/Typescript

Angular 2 - 停止 NgClass 不断更新

javascript - 如何为将方法放在全局命名空间(窗口)上的库编写 Typescript 定义文件?

typescript - 将 slick-carousel 与 typescript 一起使用

css - 基于另一个创建新的字符串文字类型