TypeScript 类型安全失败 JSON.parse
TypeScript type-safety fails with JSON.parse
我是不是错了,或者在解析时类型安全在 TypeScript 中被抛出 JSON?
我应该在这里得到一个错误,但我没有:
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
returns 一个 any
。由于 any
包含任何类型(包括未定义),因此 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();
这不会产生 TypeError。 JSON.parse()
没什么特别的,只是一个 'problem' 加上任何 returns any
。
查看 this excellent TS book 以了解有关 any
的更多信息。
我认为问题的核心是为什么三元表达式的第二项 undefined
被允许作为分配给 Person
的替代项之一。 This Github issue 将此描述为按预期工作。整个三元表达式得到第一个 return 类型和第二个类型的并集,即 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
}
(source)
I’m thinking the inconsistency here is that, in the first case, the entire ternary expression is inferred as any | undefined which collapses to just any; the compiler therefore sees a single return any and all is right with the world (even though it’s not). In the second case there are two return sites: one is return any which again is fine, and one is return undefined which is not.
I think the challenge is that a ternary isn't really a statement but an expression. An expression must have a single type; in this case that type happens to be any | undefined which is unsound simply by the nature of any. Changing this, I suspect, would be very difficult: what happens when you have a ternary in the middle of a statement, e.g. as an argument to a function? What happens when there are several ternaries in the same statement [...]
In order to type check the above the way you suggest, the compiler would basically have to duplicate the statement and individually type check it for every combination of true/false for every single ternary in the statement. You'd have a combinatorial explosion.
The current behavior is, I suspect, the best we're going to get.
我是不是错了,或者在解析时类型安全在 TypeScript 中被抛出 JSON?
我应该在这里得到一个错误,但我没有:
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
returns 一个 any
。由于 any
包含任何类型(包括未定义),因此 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();
这不会产生 TypeError。 JSON.parse()
没什么特别的,只是一个 'problem' 加上任何 returns any
。
查看 this excellent TS book 以了解有关 any
的更多信息。
我认为问题的核心是为什么三元表达式的第二项 undefined
被允许作为分配给 Person
的替代项之一。 This Github issue 将此描述为按预期工作。整个三元表达式得到第一个 return 类型和第二个类型的并集,即 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
}
(source)
I’m thinking the inconsistency here is that, in the first case, the entire ternary expression is inferred as any | undefined which collapses to just any; the compiler therefore sees a single return any and all is right with the world (even though it’s not). In the second case there are two return sites: one is return any which again is fine, and one is return undefined which is not.
I think the challenge is that a ternary isn't really a statement but an expression. An expression must have a single type; in this case that type happens to be any | undefined which is unsound simply by the nature of any. Changing this, I suspect, would be very difficult: what happens when you have a ternary in the middle of a statement, e.g. as an argument to a function? What happens when there are several ternaries in the same statement [...]
In order to type check the above the way you suggest, the compiler would basically have to duplicate the statement and individually type check it for every combination of true/false for every single ternary in the statement. You'd have a combinatorial explosion.
The current behavior is, I suspect, the best we're going to get.