打字稿,JSON.parse 错误:“类型 'null' 不可分配给类型 'string'。”

Posted

技术标签:

【中文标题】打字稿,JSON.parse 错误:“类型 \'null\' 不可分配给类型 \'string\'。”【英文标题】:Typescript, JSON.parse error: "Type 'null' is not assignable to type 'string'."打字稿,JSON.parse 错误:“类型 'null' 不可分配给类型 'string'。” 【发布时间】:2019-07-09 22:43:54 【问题描述】:

错误发生在这里:

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

我发现 this answer 是有道理的,但是在此重构之后我仍然收到该错误:

正如错误所说,localStorage.getItem() 可以返回字符串或 null。 JSON.parse() 需要一个字符串,所以你应该在尝试使用它之前测试 localStorage.getItem() 的结果。

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);
  

我首先将localStorage moonPortfolio 的结果设置为一个var,然后检查该var 是否为typeof 字符串。仍然收到打字稿错误?

这里有什么想法或方向吗?

【问题讨论】:

【参考方案1】:

简单修复:

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

似乎 TS 确实知道 localStorage/sessionStorage 的内部工作原理。如果您尝试获取未设置的密钥,它将返回 nullnull 当被视为 boolean 时是假的,因此通过添加 OR 将使用空的字符串化 json 对象,这意味着 JSON.parse(x) 将始终被赋予一个字符串,这意味着它是安全的。

【讨论】:

感谢您提供如此简单的修复!【参考方案2】:

编译器不太了解localStorage.getItem 的内部工作原理,并且不会假设从getItem 的一次调用到下一次调用的返回值相同。所以它只是告诉你,在第二次调用getItem 时无法确定结果不是null

尝试简单地传入您已经创建的变量,而不是再次从localStorage 读取:

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

【讨论】:

谢谢! 10 分钟.... 也刚刚发现这也有效:JSON.parse(localStorage.getItem('moonPortfolio') || ''); @Leon True 并且如果在 single 空字符串的边缘情况下(JSON.parse('') 抛出 SyntaxError),该选项可能会更安全,但我仍然会对于无效字符串,更喜欢显式类型检查和 try/catch【参考方案3】:

TypeScript 不知道使用相同的字符串文字多次调用 localStorage.getItem 将始终返回相同的值(事实上,这甚至不是真的)。​​

localStorage.getItem('moonPortfolio') 的第二次调用很可能会返回null - 您应该调用JSON.parse(storedPortfolio) 而不是再次调用getItem

【讨论】:

nullJSON.parse 的有效值(不会引发错误,返回 null) - JSON.parse 的第一个参数的类型 def 不应该是 string | null ? 不,因为 JSON.parse 的第一步是将其参数隐式强制转换为字符串。 JSON.parse(32)“成功”出于同样的原因,但也是不允许的。 这种行为(无论是否隐含)是否应该被分型所覆盖? 没有?您不希望 parseInt(true) 没有类型错误。见***.com/questions/41750390/… 我想说返回 NaN 与返回变量值不同 - 尽管如此,您在该问题中所写的内容似乎可以作为文档,并清楚地概述了 TypeScript 做什么和不做什么.【参考方案4】:

要知道的主要事情是 localStorage.getItem() 返回字符串 |空值。知道我们可以用更简单的模式重写代码:

  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...
    //
  

【讨论】:

以上是关于打字稿,JSON.parse 错误:“类型 'null' 不可分配给类型 'string'。”的主要内容,如果未能解决你的问题,请参考以下文章

打字稿验证道具中的 JSON 解析

在打字稿中将 JSON 转换为字符串数组

如何通过两个对象打字稿角度6进行比较

将 localStorage.getItem() 与打字稿一起使用

打字稿:类型'null'不可分配给类型错误

打字稿错误 - 属性“标题”的类型不兼容