typescript - Omskriven parameter förlorar sin härledda typ när den är i ett annat block
Som exempel kommer jag att använda en funktion som tar emot ett argument och returnerar en funktion som alltid returnerar ett nummer. Jag kommer att ha två möjliga resultat:
om jag konverterar argumentet i det första blocket kommer returtypen att gå förlorad
// foo(bar: string | number) => () => string | number function foo(bar: string | number) { bar = +bar; return function () { return bar; } }om jag konverterar argumentet i den andra blocket kommer returtypen att härledas korrekt:
// foo2(bar2: string | number) => () => number function foo2(bar2: string | number) { return function () { return +bar2; } }
Varför går typen på en omdefinierad parameter förlorad?
Svar #1
TypeScript-kompilatorn använder kontrollflödesbaserad typanalys för att härleda smalare typer av variabler. Som du nämner, när du tar bar: string | number och sätter det till +bar, kommer värdet av bar definitivt att vara ett number strax därefter. Under resten av scopet, om du inte definierar om bar igen, kommer TypeScript att veta att bar är ett number.
Bortsett från när det inte gör det. Att returnera den anonyma funktionen function(){return bar;} introducerar en closure där värdet av bar kommer att förbli obeaktat på obestämd tid tills dess att den returnerade funktionen anropas. Vid denna punkt ger TypeScript-kompilatorn upp. Den vet inte om någon kommer att ändra värdet av bar till en string innan den funktionen anropas, så den behåller inte den avgränsade typen inom closuren.
»Vänta«, kanske du säger, »genom att inspektera kan jag se att ingenting kan hända med värdet av bar efter att jag returnerar den funktionen, så det är alltid ett number för alltid.« Och du har förmodligen rätt. Tyvärr är kompilatorn inte lika smart som du, och att ge upp när man stöter på en closure är bara en av många heuristiker som används för att hålla problemet med kontrollflödesanalys hanterbart.
Det finns ett utmärkt ärende på GitHub om svårigheten med att få kontrollflödesanalys att bli "rätt": Microsoft/TypeScript #9998: Trade-offs in Control Flow Analysis. Det finns många fall där kompilatorn kan luras till att antingen misslyckas med att smalna av en typ (ofullständighet) eller över-smalna en typ (osäkerhet). Det är bara så det är, åtminstone tills vi når den teknologiska singulariteten.