Typescript - nästlad map-typ ger förvirrande typförslag
Jag har skrivit en nästlad Omit-typ på två olika sätt, men den som verkar mest logisk för mig ger förvirrande typförslag medan den som är mindre intuitiv faktiskt ser bäst ut. Här är den:
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
Att tilldela fel typ till T7.b.d eller T7.a.d berättar t.ex. string is not assignable to number, men jag förstår inte varför användning av Exclude<keyof T[P1], K2> ger så komplicerad typning trots att P1 in keyof T och P1 extends K1, och Exclude<keyof T[K1], K2> ger de korrekta typerna.
Svar #1
Det här ser ut som ett fel i kompilatorn för mig. Jag har precis lämnat in Microsoft/TypeScript#31326 och kommer att rapportera tillbaka med uppdaterad information därifrån. Lycka till!
UPPDATERING, 2019-05-10: Detta har markerats som ett fel av en av språkteknikerna. Vet inte när det kommer att åtgärdas, men åtminstone vet vi att du har rätt att vara förvirrad över den typinformationen.
UPPDATERING, 2019-05-11: Som du märkte är denna bugg nu fixad och har sammanfogats i master. Det betyder att om du nu testar din kod med typescript@next bör du se det nya beteendet:
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 }
Jag ser ingen skillnad mellan dina T6 och T7 typer längre. Så, det verkar som att detta helt orsakades av den kompilatorbuggen, och bör försvinna när TypeScript 3.5 släpps omkring den 30 maj 2019.
Okej, lycka till!
