TypeScript映射的类型值取决于键

时间:2019-02-25 23:31:15

标签: typescript typescript-typings typescript-generics

我可以根据项目的键约束地图条目的值类型吗?

type Thing<T extends string = any> = {
    type: T
}

type ThingMap<T extends Thing> = {
    [K in T["type"]]: T
}

interface A {
    type: "A",
    foo: boolean,
}

interface B {
    type: "B",
}


// This compiles.
const map: ThingMap<A | B> = {
    A: { type: "A", foo: true },
    B: { type: "B" },
}

// But this also compiles, when it should not.
const map: ThingMap<A | B> = {
    A: { type: "A", foo: true },
    B: { type: "A", foo: true },
}

1 个答案:

答案 0 :(得分:2)

您要确保对于特定的K,密钥的类型不是整个联合(即T),而只是类型为K的联合成员。您可以使用Extract获取具有类型type的属性K的并集成员:

type Thing<T extends string = any> = {
    type: T
}

type ThingMap<T extends Thing> = {
    [K in T["type"]]:  Extract<T, { type : K }>  // Extract the union member that has { type: K }
}

interface A {
    type: "A",
    foo: boolean,
}

interface B {
    type: "B",
}


// This compiles.
const map: ThingMap<A | B> = {
    A: { type: "A", foo: true },
    B: { type: "B" },
}

// Err now
const map2: ThingMap<A | B> = {
    A: { type: "A", foo: true },
    B: { type: "A", foo: true },
}