简体   繁体   中英

Typescript, JSON.parse error: "Type 'null' is not assignable to type 'string'."

The error was happening here:

let moonPortfolio;
...
moonPortfolio = JSON.parse(localStorage.getItem('moonPortfolio'));

I found this answer which makes sense, however I'm still getting that error after this refactor:

As the error says, localStorage.getItem() can return either a string or null. JSON.parse() requires a string, so you should test the result of localStorage.getItem() before you try to use it.

if (portfolio.length === 0) {
  const storedPortfolio = localStorage.getItem('moonPortfolio');

  if (typeof storedPortfolio === 'string') {
    moonPortfolio = JSON.parse(localStorage.getItem('moonPortfolio'));
  }
  else {
    moonPortfolio = [];
  }

  if (moonPortfolio) {
    const savedPortfolio = Object.values(moonPortfolio);
    this.props.fetchAllAssets();
    // this.props.addCoins(savedPortfolio);
  }
}

在此处输入图像描述

I first set the results of localStorage moonPortfolio to a var, then check if the var is typeof string. Yet still getting the typescript error?

Any thoughts or direction here?

The compiler doesn't know too much about the inner workings of localStorage.getItem and doesn't make the assumption that the return value will be the same from one call of getItem to the next. So it just tells you that it can't be certain that on the second call to getItem the result isn't null .

Try simply passing in the variable you've already created instead of reading from localStorage again:

if (typeof storedPortfolio === 'string') {
  moonPortfolio = JSON.parse(storedPortfolio);
}

Simple fix:

JSON.parse(localStorage.getItem('moonPortfolio') || '{}');

Seems like TS does know about the inner workings of localStorage/sessionStorage actually. It returns null if you try to fetch a key that isn't set. null when treated as boolean is falsy so by adding OR the empty stringified json object will be used instead meaning that JSON.parse(x) will always be given a string meaning it's then type safe.

TypeScript doesn't know that multiple invocations of localStorage.getItem with the same string literal will always return the same value (in fact, this isn't even true).

The second call to localStorage.getItem('moonPortfolio') may well return null - you should call JSON.parse(storedPortfolio) instead of calling getItem again.

The main thing to know is that localStorage.getItem() returns string | null. Knowing that we can re-write the code with a simpler pattern:

  const portfolio = []; //Just to make the code samples valid
  if (portfolio.length === 0) {
    let moonPortfolio = []; //Default value
    const storedText = localStorage.getItem('moonPortfolio');
    if (storedText !== null) { //We know it's a string then!
      moonPortfolio = JSON.parse(storedText);
    }
    //The if statement here is not needed as JSON.parse can only return 
    //object | array | null or throw. null is the only falsy value and that 
    //can only happen if storedText is null but we've already disallowed 
    //that.
    //if (moonPortfolio) {
      const savedPortfolio = Object.values(moonPortfolio);
      //Do whatever else is needed...
    //}
  }

also in react:

JSON.parse(localStorage.getItem("data") ?? '{}')

or

JSON.parse(localStorage.getItem("data") || '{}')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM