Typescript utelämnar inte typer korrekt
Jag försöker skapa en funktion som tar antingen ett nummer eller strängen 'last' och använder motsvarande element från en array.
Jag hanterar fallet där indata är 'last'.
Jag har lagt till ett förenklat exempel. TS Playground
Jag får ett fel på raden return state[i].
Jag försökte flytta dispatch... till ett if-block med (typeof i === 'number') men det fungerar inte heller.
export function moveTo(i: number | 'last') {
return (dispatch: Function, getState: ()=>string[]) => {
const state = getState();
if (i === 'last') {
i = state.length - 1;
}
dispatch({
index: i, //here i is shown to be number on hover
effect() {
return state[i]; // index expression is not of type number (shows as number | 'last')
}
});
};
}
Jag vill hävda efter if-satsen att i är number så att jag inte behöver använda as number överallt i effektfunktionen.
Svar #1
Eftersom i kan vara en string och en number, har linter svårt att förstå konverteringen. En lösning är att använda en annan variabel:
export function moveTo(i: number | 'last') {
return (dispatch: Function, getState: ()=>string[]) => {
const state = getState();
const index: number = (i == 'last') ? state.length - 1 : i;
dispatch({
index,
effect() {
return state[index];
}
});
};
}
Dessutom är det dåligt att ha flera typer för samma variabel (eftersom sådana saker kan inträffa), jag föreslår att använda -1 istället för 'last' för att hålla sig till number-typen.
Svar #2
Typen för i i effect-callbacken är inte begränsad, eftersom i betraktas som en förändringsbar parameter i funktionen moveTo.
Det betyder att när effect-callbacken anropas någon gång senare, kan inte kompilatorn vara säker på att i fortfarande har typen number. Som en följd blir typvakten som induceras av if (i === 'last') {i=state.length - 1;} ogiltig, och i får den ursprungliga typen number | 'last' i callbacken.
Så när anser TS att funktionsparametrar är const?
Funktionsparametrar behandlas implicit som const, tills du gör en tilldelning till parametern någonstans i funktionen eller en nästlad funktion. När en parameter är en implicit const är dess avsmalnade typ fortfarande åtkomlig i nästlade funktionsuttryck och arrow-funktioner via kontrollflödesanalys/typ-skärmar. Så detta konstruerade exempel fungerar:
export function moveTo(i: number | 'last') {
return (dispatch: Function, getState: () => string[]) => {
if (i !== 'last')
dispatch({
index: i,
effect() {
return getState()[i];
}
})
};
}
Och vad ska man göra nu?
Det bästa alternativet är förmodligen att deklarera en ny const-variabel (se även @D. Nathanaels svar), vilket ger mer konsekventa typer än as number-kast i callbacken. Airbnb JavaScript Style Guide rekommenderar inte omtilldelning av funktionsparametrar, så du kan se det som en möjlighet att städa upp koden lite genom att behandla i som oföränderlig.
