使用其他类型的属性名创建区分联合

时间:2017-05-10 17:20:14

标签: typescript

我正在尝试创建一个泛型类型,它从类型中获取属性名称和属性类型,并使用它们来创建区别性的联合类型。例如:

type FooBar = {
    foo: string;
    bar: number;
};

将映射到:

type FooBarPair = {
    key: "foo",
    value: string
} | {
    key: "bar",
    value: number
}

我最初的尝试是:

type Pairs<T> = {
    [TKey in keyof T]: {
        key: TKey;
        value: T[TKey];
    };
};

type Pair<T> = Pairs<T>[keyof T];

但是当我尝试将其应用于上述类型时:

let pair: Pair<FooBar> = {
    key: "foo",
    value: 3
};

我希望编译错误,但是没有。当我检查Pair<FooBar>的类型时,我发现它等同于:

{
    key: "foo" | "bar";
    value: string | number;
}

我认为这可能是打字稿中的一个错误,但我想知道是否还有其他方法可以实现这一目标。

1 个答案:

答案 0 :(得分:3)

是的,有办法实现这一目标。事实证明,Typescript推断出所需的类型

 `{ key: "foo"; value: string; } | { key: "bar"; value: number; }`

删除中间通用类型type Pair<T> = Pairs<T>[keyof T];并在每次使用时将其展开为Pairs<FooBar>[keyof FooBar]内联:

type Pairs<T> = {
    [TKey in keyof T]: {
        key: TKey;
        value: T[TKey];
    };
};

type FooBar = {
    foo: string;
    bar: number;
};


let pair: Pairs<FooBar>[keyof FooBar] = {
    key: "foo",
    value: 3
};

完整的错误消息是

Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; } | { key: "bar"; value: number; }'.
  Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; }'.
    Types of property 'value' are incompatible.
      Type 'number' is not assignable to type 'string'.

我不确定在任何一种情况下推断的“正确”类型是什么,但像Pair<T> = Pairs<T>[keyof T]这样的速记类型的引入不应该影响类型推断IMO。看起来像一个错误。