javascript - Typescript: kartesisk produkt av två generiska arrayer resulterar i fel typ som härleds


Jag skrev en enkel implementation av kartesisk produkt i Typescript, men typen som härleds är inte vad jag förväntade mig:

export function cartesianProduct<X, Y> (a: X[], b: Y[]): Array<[X, Y]> {
    return a.flatMap(x => b.map(y => [x, y]));
}

Som du kan se är den härledda typen (X | Y)[][] istället för [X, Y][]. Detta verkar konstigt för mig eftersom [x, y] borde ha typen [X, Y] (x är av typen X och y är av typen Y). Någon idé om varför jag får detta typefel och hur man fixar det?

Svar #1

TypeScript härleder generellt arrayliteraler som [x, y] till att ha arraytyper istället för tuplet-typer. Om du vill ändra detta behöver du ge typkontrollanten kontext för vilken typ den ska härleda annorlunda. Det finns olika sätt att göra detta på (till exempel en const-påstående, eller använda ett typ-påstående med as-operatorn, eller genom att manuellt specificera den generiska typeargumentet till map som map<[X, Y]>).

För närvarande är det tillvägagångssätt jag mest skulle rekommendera att använda satisfies-operatorn; om du skriver expr satisfies Type kommer det att tala om för kompilatorn att använda Type som kontext för att härleda expr:s typ. Om den kan härleda en kompatibel typ kommer den att göra det; annars kommer den att generera ett fel, så satisfies-operatorn är typ-säker på ett sätt som en typförklaring inte är.

Så allt du behöver göra är detta:

function cartesianProduct<X, Y>(a: X[], b: Y[]): Array<[X, Y]> {
    return a.flatMap(x => b.map(y => [x, y] satisfies [X, Y]));
}

Och det fungerar.

Lekplatslänk till kod

Svar #2

Typescript är förvirrat över dina typer. Din kod får det att verka som om du vill ha en array som returnerar fler arrayer som har en blandning av dina X och Y. Det verkar dock som om du vill ha en array av par som skulle vara [X, Y].

För att åtgärda ditt fel måste du definiera att de inre arrayerna ska vara [X, Y]. Så här:

export function cartesianProduct<X, Y>(a: X[], b: Y[]): Array<[X, Y]> {
return a.flatMap((x: X) => b.map((y: Y) => [x, y] as [X, Y]));

}