簡體   English   中英

打字稿中的聯合類型推斷

[英]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的存在與否來區分p1p3 是的,如果你只是想說const demo: p3 = {a: '123', b: '123'}你會在"b"上得到一個過多的屬性警告,但這正如我所說,只是為了方便. 很容易被打敗:

const demo1 = { a: '123', b: '123' };
const demo2: p3 = demo1; // no error

此時您可能想知道:“等等,如果"b"沒有正確區分p1p3 ,為什么編譯器認為它在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區分p1p3 ,那么您的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定義區分p1p3

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM