Home > Net >  Typescript: Why doesn't typeguard work with previous state
Typescript: Why doesn't typeguard work with previous state

Time:02-15

When making a simple rock, paper, scissors game with typescript I cam across an interaction I couldn't understand.

const [gameState, setGameState] = useState<gameState>({
    choice: null,
    score: 0,
  });

function fetchScore() {
    let score = localStorage.getItem("score");
    if (typeof score === "string") {
      setGameState((prev) => ({ ...prev, score: 
      parseInt(score) })); // Typescript still thinks score can be null
    } 
}

parseInt throws an error saying score could be set to null despite the type guard.

I did some messing around and found that it was only happening when I used prev state.

 const [test,setTest] = useState(0);

 function fetchScore() {
    let score = localStorage.getItem("score");
    if (typeof score === "string") {
      setTest(parseInt(score))//Score is correctly guarded
    } 
  }

I am currently handling it by typecasting score as a string but I would like to understand what cause this to happen?

CodePudding user response:

That is because you are using score inside of a callback function. So typescript assumes that score variable can be changed before callback function will be executed and score potentially can null inside callback function. Solutions: the best solution I see is to use const instead of let.

const score = localStorage.getItem("score");

this way typescript know that score cannot be changed later.

Also you could check typeof score inside of callback function and typescript will not complaine. I would prefer const. But this will work too. Just for understanding how it works here:

function fetchScore() {
  let score = localStorage.getItem("score");
  setGameState((prev: any) => {
    if (typeof score === "string") {
      // no complaining, checking inside of callback function
      return { ...prev, score: parseInt(score) };
    }
    return prev;
  });
}
  • Related