网站搜索

为什么 TypeScript 联合类型 + 映射类型在有泛型和没有泛型时表现不同


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

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

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

我如何在没有 Calc 和 Generics 的情况下得到 Calc<BaseA> | Calc<BaseB>。

我如何使用 泛型 获得 { type: "A" | "B"; flag: number; }。

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

答案#1

第一个问题很容易解决:

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 替换内部映射。

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

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

第二个问题有点棘手。它是由分配条件类型引起的。我发现只有使用这个技巧才能禁用分配性:

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

type Q2 = Calc2<[Base]>

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

操场