Typescript-嵌套的地图类型提供了令人困惑的类型提示

时间:2019-05-08 23:16:13

标签: typescript typescript-generics

我用两种不同的方式编写了一个嵌套的Omit类型,但是对我来说更有意义的一种类型给出了复杂的类型提示,而一种较不直观的类型提示实际上看起来最好。去吧:

type HasSameNested = {
    a: {
        c: number; d: string
    },
    b: {
        c: string; d: number
    }
}; // flipped C and D types

type Omit2<T, K1 extends keyof T, K2 extends keyof T[K1]> = {
    [P1 in keyof T]: P1 extends K1 ? {
        [P2 in Exclude<keyof T[K1], K2>]: T[P1][P2]
    } : T[P1]
}

type Omit2_2<T, K1 extends keyof T, K2 extends keyof T[K1]> = {
    [P1 in keyof T]: P1 extends K1 ? {
        [P2 in Exclude<keyof T[P1], K2>]: T[P1][P2]
    } : T[P1]
}

type omit_union = Omit2<HasSameNested, 'a' | 'b', 'c'>;
let T6: omit_union;
T6.a; // works, type is { d: string }
T6.b; // works, type is { d: number }

type omit_union_2 = Omit2_2<HasSameNested, 'a' | 'b', 'c'>;
let T7: omit_union_2;
T7.a.d = 'a'; // works but types are ugly:
// a: { [P2 in Exclude<keyof HasSameNested[K1 & "a"], "c">]: HasSameNested[K1 & "a"][P2]; }
// d: d: HasSameNested[K1 & "a"]["d"]

T7.b.d = 4; // works but types are ugly, as above

将错误的类型分配给T7.b.dT7.a.d确实会告诉我string is not assignable to number,但我不明白,即使Exclude<keyof T[P1], K2>P1 in keyof TP1 extends K1,为什么使用Exclude<keyof T[K1], K2>仍会产生这种复杂的输入给出正确的类型。

1 个答案:

答案 0 :(得分:2)

在我看来,这似乎是编译器中的错误。我刚刚提交了Microsoft/TypeScript#31326,并将从那里报告最新信息。祝你好运!

更新,2019年5月10日:一位语言设计师将其标记为bug。不知道何时将其修复,但至少我们知道您对该类型信息感到困惑是正确的。

更新,2019年5月11日:正如您所注意到的那样,此错误现在为fixed,并已合并到master中。这意味着,如果您现在使用typescript@next尝试代码,则应该看到新的行为:

type omit_union_2 = Omit2_2<HasSameNested, 'a' | 'b', 'c'>;
declare let T7: omit_union_2;
T7.a; // works, type is { d: string }
T7.b; // works, type is { d: number }

我看不到您的T6T7类型之间的区别。因此,看起来这完全是由该编译器错误引起的,并且应该在2019年5月30日左右发布TypeScript 3.5时消失。

好的,祝你好运!