typescript / expert
Snippet
Typprüfungen zur Compile-Zeit mit Equal und Expect
Equal vergleicht zwei Typen, indem zwei generische Funktionssignaturen über ihnen geprüft werden – streng genug, um `any` und `unknown` zu unterscheiden und strukturelle Beinahetreffer abzulehnen. Expect verlangt, dass das Argument `true` ist, sodass die Zusicherung im Typsystem lebt und Drift einen Build-Fehler erzeugt. Es ist das Standardmuster, um Typ-Utilities ohne Laufzeitcode zu testen.
snippet.ts
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Equal<X, Y> =(<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;type Expect<T extends true> = T;type ParseQuery<S extends string> =S extends `${infer K}=${infer V}&${infer Rest}`? { [P in K]: V } & ParseQuery<Rest>: S extends `${infer K}=${infer V}`? { [P in K]: V }: Record<string, never>;// These lines fail to compile if the parser ever regresses:type _t1 = Expect<Equal<ParseQuery<'a=1&b=2'>, { a: '1' } & { b: '2' }>>;type _t2 = Expect<Equal<ParseQuery<''>, Record<string, never>>>;
Erklärung
1
(<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false
Der Vergleich geschlossener generischer Signaturen macht die Prüfung invariant und zuverlässig.
2
type Expect<T extends true> = T;
Die Constraint `extends true` lehnt jedes Ergebnis außer dem Literal true ab.
3
S extends `${infer K}=${infer V}&${infer Rest}`
Template-Literal-Inferenz spaltet den Query-String am ersten `&`.
4
? { [P in K]: V } & ParseQuery<Rest>
Pro Paar entsteht ein Schlüssel/Wert-Objekt; beim Rückrollen werden sie geschnitten.
5
type _t1 = Expect<Equal<ParseQuery<'a=1&b=2'>, ...>>;
Entweder passt das Parser-Ergebnis exakt oder die Datei kompiliert nicht.