我错了吗?还是在解析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 | undefined
与any
相同。
使用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组合的类型。你会得到一个组合爆炸。
我怀疑,目前的行为是我们能得到的最好的。