Typescript infer-nøkkelordet utleder feil type?
Med en enkel konstruksjon som dette:
type Test<Source extends string[]> =
Source extends [infer Head, ...infer Tail] ? `${Head}${Head}` : never;
Typescript klager på strenginterpolasjonen inne i $ {Head}$ {Head} og sier: Type `'Head'` kan ikke tilordnes til typen 'string | number | bigint | boolean'. Type 'Head' kan ikke tilordnes typen 'number'.ts(2322)
...som ikke gir mye mening for meg, men søkene mine ga ikke noe resultat. Kilden må være en string[], så Head, hvis den eksisterer, må jo være en streng, ikke sant? Så $ {Head} må være helt gyldig. Hvorfor klager TS på at den ikke kan tilordnes til en number? Streng kan også tilordnes til "string | number | bigint | boolean", så denne feilen gir ikke mye mening for meg. Jeg kan fikse det ved å plassere strenginterpolasjonen mellom en "Head extends string ? ... : ...-klausul, men jeg lurer på hvorfor det er nødvendig i første omgang.
Svar #1
Ja og nei. Ta en titt på neste eksempel:
type Test0<Source extends string[]> =
Source extends [infer Head, ...infer Tail] ? Head : never;
type O = Test0<[never, 'a']> // no error, because that is how NEVER works
Fordi string|never returnerer string.
Jeg synes det er mye tryggere å sjekke om Head er en streng eller ikke i ovennevnte tilfelle.
Svar #2
Årsaken til feilen er at TypeScript ikke tar hensyn til extends string[]-begrensningen før den har utledet typene. Hvis du ser på denne typen
type T<Head> = `${Head}`
du vil se den samme ganske uklare feilmeldingen (slutning for template literals er litt ustødig). Siden T ikke slutter Head her, kan du selvsagt bare erklære type T<Head extends string>=.., men et annet alternativ er å kode Head extends string-begrensningen i en ekstra betingelse:
type T<Head> = Head extends string ? `${Head}` : never
Dette er grunnen til at Test typetester hvis du legger til den ekstra, tilsynelatende overflødige, betingelsen:
type Test<Source extends string[]> =
Source extends [infer Head, ...infer Tail]
? Head extends string ? `${Head}${Head}` : never
: never;
TypeScript-lekeplass
