type p1 = { a: number, b: string }
type p3 = { a: string }
type p4 = p1 | p3
let demo: p4 = { a: '123', b: '123' }
function isP3(obj: p4): obj is p3 {
return typeof (<p3>obj).a === 'string'
}
function func(obj: p4) {
if ('b' in obj) {
// Uncaught TypeError: obj.a.toFixed is not a function
obj.a.toFixed() //<- Now, no error is given
} else {
}
}
func(demo)
为什么演示在初始化时没有报告错误? 用户定义的类型保护器
答案 0 :(得分:1)
这是TypeScript中的open issue (microsoft/TypeScript#20863)。您的联合类型不是discriminated union,因此编译器不会在执行excess property checking之前将联合分成成员。大多数人(包括我自己在内)都希望对工会的每个成员都进行多余的财产检查,而不管工会是否是受歧视的工会。不过,目前只是这样:编译器认为"b"
是至少一个工会成员中可接受的属性,并决定不抱怨。
请注意,检查多余的属性是一种方便,而不是类型安全问题。 TypeScript中的对象类型为 open ,您可以始终在定义中添加更多属性,而不会违反类型。尽管具有{x: 1, y: 2}
属性,值{x: number}
仍然是有效的y
。换句话说,TypeScript中的对象类型不是exact。因此,从技术上讲,{ a: '123', b: '123' }
是有效的p3
,因此也是有效的p4
。因此,从技术上讲,您不能仅仅检查是否存在b
来区分p1
和p3
。是的,如果您只是尝试说const demo: p3 = {a: '123', b: '123'}
,则会在"b"
上收到财产过剩警告,但是正如我所说的那样,这只是一种方便。它很容易被击败:
const demo1 = { a: '123', b: '123' };
const demo2: p3 = demo1; // no error
这时您可能会想:“等等,如果"b"
不能正确地区分p1
与p3
,为什么编译器会认为它在func()
内部起作用? ”。好问题:
if ('b' in obj) { // why does the compiler think this narrows obj to p1?
obj.a.toFixed() // no error, but blows up at runtime
}
好吧,事实证明the in
type guard is intentionally unsound。从技术上讲,使用它并不安全,但是人们可以这样做,通常这不是问题。但这对您没有帮助。哦,很好。
那么,您应该在这里做什么?如果您打算测试b
和p1
之间的区别,则您的p3
类型应明确说明:
p3
现在type p3 = { a: string, b?: undefined }; // p3 cannot have a defined "b" property
类型是as of TypeScript 3.2+,是一个真正的有区别的联合。所以这是一个错误:
p4
并使不健全的let demo: p4 = { a: '123', b: '123' } // error now
测试显示为错误。如果您想做一个“好”的'b'
测试,现在就可以测试b
了,它肯定会用新的{{1来区分obj.b !== undefined
和p1
}}定义:
p3
好的,希望能有所帮助;祝你好运!
答案 1 :(得分:0)
使用自定义类型保护功能来缩小类型的范围,而不是'b' in obj
if (!isP3(obj)) {
obj.a.toFixed() // Error
} else {
}
}
关于作业let demo: p4 = { a: '123', b: '123' }
,我也很困扰,没有给出错误。如我所知,如果我们将a
定义为布尔值而不是数字,它将可以正常工作(这意味着给出错误)。看起来只有分配器类型包含联合类型本身时分配才会失败。您可以订阅此问题以获取详细信息https://github.com/microsoft/TypeScript/issues/35861
有关此问题的规范部分并未完全解释当前的行为。看起来像是一种解释,必须先了解一下编译器本身。 https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#34-union-types