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

Relaterte artikler