P粉9577231242023-07-29 09:49:07
你說得對,TypeScript不允許你存取它不知道變數類型上可能存在的屬性。如果該類型是聯合類型,那麼在TypeScript允許你存取之前,該屬性必須存在於該聯合類型的所有成員上。
但是可以透過各種方法來縮小變數的類型。例如,你可以先檢查值是否為true,如果不是,則TypeScript會將聯合類型縮小為僅為ValidationError。
通常,另一個選擇是使用in運算符,但在這種情況下,聯合類型不僅包含物件類型,所以TypeScript不允許使用它。
你也可以定義一個自訂類型保護(或使用庫中提供的類型保護,如果存在的話),但對於這種簡單的情況來說,這似乎可能是你想要的工作量有點太大。
正如我提供的TypeScript文件詳細說明的那樣,還有其他縮小類型的方法。像你提到的,檢查typeof運算子的結果也是其中的一種方法。
這個例子只是宣告了一個型別保護存在,而不是實作一個,但是下面是你可以使用每種方法來縮小result變數類型的方式:
declare type ValidationError = { err: unknown }; declare function isValidationError(val: unknown): val is ValidationError; declare const XMLValidator: { validate(message: unknown): true | ValidationError }; const message = 'test message'; const result = XMLValidator.validate(message) // You can check first if the result is `true` if (result === true) { // Handle success } else { // Then the `else` branch knows it much be a `ValidationError` console.error(result.err); } // Normally allowed, but not in this case. Error: // Type 'true | ValidationError' is not assignable to type 'object' if ('err' in result) { console.error(result.err) } if (isValidationError(result)) { console.error(result.err); }#
雖然它們通常最好避免使用,但你也可以使用TypeScript的as關鍵字來進行型別斷言。
之所以最好避免使用這些類型斷言,是因為你告訴TypeScript將一個類型視為其他類型。因此,透過這樣做,你可能會犧牲類型安全性。
console.error((result as ValidationError).err);
然而,在你對情況的理解比TypeScript編譯器更好的情況下,這是你可以使用的工具,以向它提供更多資訊。
就我個人而言,我發現這是一種有幫助的方法,總是留下註釋解釋為什麼使用了類型斷言,提及其安全性基於的任何假設。
此外,在這種情況下,使用類型斷言來檢查屬性不會縮小result變數的類型,所以這種方法可能不完全符合你的需求。