typescript - Varför kan inte detta villkor med generisk keyof lösas direkt?


function broken<T>(value: T) {
  type Test = keyof T extends keyof T ? 1 : 0
}

Varför kan inte Test i exemplet ovan lösas direkt till 1? Det är något jag inte förstår om kompilatorn som borde svara på den här frågan åt mig.

Intressant nog finns det en lösning:

function workaround<T>(value: T) {
  type Test = [keyof T] extends [keyof T] ? 1 : 0
}

Lekplats här

Svar #1

Svaret på frågan involverar förmodligen en buggfix som introducerades i TypeScript 3.3. Beskrivningen av det nya sättet att utvärdera villkorliga typer är:

För en konditionell typ T extends U ? X : Y, är algoritmen vi använder för att avgöra om vi ska skjuta upp upplösningen av en konditionell typ:

  • vi löser oss till Y när T inte är tilldelbar till U med beaktande av alla typparametrar som refereras i T och U relaterade (dvs. T är definitivt inte tilldelbar till U),
  • annars löser vi till X när T kan tilldelas U med hänsyn till alla typparametrar som refereras i T och U som orelaterade (dvs. T kan definitivt tilldelas U),
  • annars skjuter vi upp lösningen.

Så det ser ut som att keyof T extends keyof T ? 1 : 0 är uppskjuten, eftersom keyof T1 inte kan tilldelas keyof T2 när T1 och T2 är orelaterade typer. Denna uppskjutning är inte exakt fel, men det verkar som en begränsning.

Faktiskt, om jag testar din kod i TS 3.2.1 löses den snabbt, så detta var en förändring som infördes för TS3.3.

Nyfiket nog ser min läsning av den buggfixens algoritmbeskrivning ut som att den borde gälla för din lösning också. Jag är inte säker på varför [keyof T] extends [keyof T] skulle ändra saker, eftersom [keyof T1] inte är definitivt tilldelningsbara till [keyof T2], om T1 och T2 inte är relaterade. Så några mysterier återstår fortfarande här. Har inte kunnat lista ut det än, så jag kommer nog bara att ge upp nu. Tja, så är det!

Det ser också ut som om någon rapporterade exakt detta problem där X extends X ? 1 : 0 inte löses snabbt (och de märkte också att inneslutning i en en-tuple "fixar" det), och problemet markerades som ett fel, så kanske det kommer att tas upp?

Okej, hoppas det hjälper; lycka till!

Relaterade artiklar