TypeScript类型安全在JSON.parse中失败



我错了吗?还是在解析JSON时,类型安全在TypeScript中被抛出?

应该在这里得到一个错误,但我没有:

interface Person {
name: string
}
const person: Person = somePossibleFalsey ? JSON.parse(db.person) : undefined

上面的代码没有通过类型检查,尽管我认为它应该通过。db.person变量可能不存在,这可能使person呈现为undefined。但Person不应该是undefined。据我所知,这是因为我使用的是JSON.parse

只是为了确认我应该得到一个错误,这里是另一个片段,正确给我一个错误:
const person: Person = Math.random() > .5 ? { name: 'Arthur' } : undefined
上面的代码会产生相应的TypsScript错误:
Type '{ name: string; } | undefined' is not assignable to type 'Person'.
Type 'undefined' is not assignable to type 'Person'.ts(2322)

为什么JSON.parse允许类型安全失败?还是另有隐情?

JSON.parse返回一个any。由于any包含任何类型(包括undefined),因此any | undefinedany相同。

使用as输入JSON.parse结果,您将得到预期的输出:

const person: Person = db.person ? JSON.parse(db.person) as Person : undefined; 
// Error: Type 'Person | undefined' is not assignable to type 'Person'. Type 'undefined' is not assignable to type 'Person'

编辑:你似乎不清楚any类型。这实际上关闭了所有类型安全。每种类型都可以分配给any,any也可以分配给每种类型。当你做

const myAnyFunc = (): any => {return undefined;};
const myPerson: Person = myAnyFunc();

this不会创建TypeError。JSON.parse()没有什么特别之处,只是任何返回any的"问题"。看看这本优秀的TS书,了解更多关于any的知识。

我认为问题的核心是为什么允许三元表达式的第二项undefined作为分配给Person的替代项之一。这个Github问题将其描述为按预期工作。整个三元表达式获得第一个返回类型和第二个返回类型(即any | undefined)的联合,后者分解为any,这反过来使其成为有效的赋值。(any是所有类型中最弱的)。相反,如果将其包装在if-else块中,则会出现错误:

let n: number;
let x: any = {}
n = x.z ? x.z : undefined // no error
let y: any = {}
if (y.z) {
n = y.z
} else {
n = undefined // error
}

(源)

我认为这里的不一致是,在第一种情况下,整个三元表达式被推断为any | undefined,它崩溃为any;因此,编译器看到一个单一的返回any和all is right with The world(即使事实并非如此)。在第二种情况下,有两个返回点:一个是return any,这也是可以的,另一个是return undefined,这是不可以的。

我认为挑战在于三元数实际上不是一个语句,而是一个表达式。表达式必须具有单一类型;在这种情况下,该类型恰好是any | undefined,从any的性质来看,这是不合理的。改变这一点,我怀疑,将是非常困难的:当你在一个语句的中间有一个三进制,例如作为一个函数的参数会发生什么?如果在同一语句中有多个三元,会发生什么情况[…]

为了按照你建议的方式进行类型检查,编译器基本上必须复制语句,并单独检查语句中每个三进制的每个true/false组合的类型。你会得到一个组合爆炸。

我怀疑,目前的行为是我们能得到的最好的。

相关内容

最新更新