[英]union type inference in typescript
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)
為什么demo初始化時沒有報錯? 用戶定義的類型保護
這是TypeScript 中的一個未解決的問題 (microsoft/TypeScript#20863) 。 您的聯合類型不是可區分的聯合,因此編譯器在執行多余的屬性檢查之前不會將聯合拆分為成員。 大多數人(包括我自己)都希望對工會的每個成員進行額外的財產檢查,無論工會是否受到歧視。 不過,就目前而言,情況就是這樣:編譯器認為"b"
是至少一個聯合成員中可接受的屬性,並決定不抱怨。
請注意,多余的屬性檢查是一種方便,而不是類型安全問題。 TypeScript 中的對象類型是open ,你總是可以在不違反類型的情況下向它們添加更多的屬性而不是定義中的內容。 盡管具有y
屬性,但值{x: 1, y: 2}
是有效的{x: number}
。 另一種說法是 TypeScript 中的對象類型並不精確。 因此,技術上正確的是{ 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
}
好吧,事實證明in
類型保護是故意不健全的。 從技術上講,使用它是不安全的,但人們會這樣做,通常這不是問題。 但這對你沒有幫助。 那好吧。
那么,你應該在這里做什么? 如果您的目的是測試b
區分p1
和p3
,那么您的p3
類型應該清楚地表明:
type p3 = { a: string, b?: undefined }; // p3 cannot have a defined "b" property
現在, 從 TypeScript 3.2+ 開始, p4
類型是一個真正的可區分聯合。 所以這是一個錯誤:
let demo: p4 = { a: '123', b: '123' } // error now
並使不健全的'b'
測試顯示為錯誤。 如果你想做一個“好”的b
測試,你現在可以測試obj.b !== undefined
,它肯定會用新的p3
定義區分p1
和p3
:
function func(obj: p4) {
if ('b' in obj) {
obj.a.toFixed() // error now
}
if (obj.b !== undefined) {
obj.a.toFixed(); // okay
}
}
好的,希望有幫助; 祝你好運!
使用您的自定義類型保護函數來縮小類型而不是'b' in obj
的'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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.