搜尋

首頁  >  問答  >  主體

JavaScript有物件包裝器,可以讓我檢查原始類型的"屬性"是否存在,那麼我該如何讓TypeScript也能像這樣運作呢?

<p>XMLValidator.validate的回傳值要不是true,就是ValidationError(這並不完全準確,請查看我的更新),而ValidationError具有err屬性。 </p> <pre class="brush:php;toolbar:false;">validate( xmlData: string, options?: validationOptionsOptional): true | ValidationError</pre> <p>因為JavaScript使用物件包裝器來表示布林原始值,所以我可以透過檢查err屬性是否存在來判斷驗證是否成功。 </p> <pre class="brush:php;toolbar:false;">const result = XMLValidator.validate(message) if (result.err) { // How do I make it work in ts? console.log(`invalid XML) } else { console.log(`XML) }</pre> <p>但是TypeScript不允許我這樣做,它會報錯:"true"類型上不存在屬性'err'。 </p><p>我不喜歡先檢查回傳類型的想法,因為我覺得它很囉嗦,而且實際上沒有傳回值類型的定義(請查看我的更新)。我應該如何編寫盡可能簡潔的TypeScript程式碼? </p><p>--- 更新 ---</p><p>我進一步檢查了validator.js的程式碼。 </p><p><br /></p> <pre class="brush:php;toolbar:false;">const isValid = validateAttributeString(attrStr, options); if (isValid !== true) { return getErrorObject(...); } … function getErrorObject(code, message, lineNumber) { return { err: { code: code, msg: message, line: lineNumber.line || lineNumber, col: lineNumber.col, }, }; }</pre> <p>所以看起來我只能在這裡使用 if (typeof result == "boolean"),但我希望有一個"通用"的解決方案來回答我的問題。 </p>
P粉797855790P粉797855790583 天前533

全部回覆(1)我來回復

  • P粉957723124

    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 Playground

    #

    雖然它們通常最好避免使用,但你也可以使用TypeScript的as關鍵字來進行型別斷言。

    之所以最好避免使用這些類型斷言,是因為你告訴TypeScript將一個類型視為其他類型。因此,透過這樣做,你可能會犧牲類型安全性。


    console.error((result as ValidationError).err);
    

    然而,在你對情況的理解比TypeScript編譯器更好的情況下,這是你可以使用的工具,以向它提供更多資訊。

    就我個人而言,我發現這是一種有幫助的方法,總是留下註釋解釋為什麼使用了類型斷言,提及其安全性基於的任何假設。

    此外,在這種情況下,使用類型斷言來檢查屬性不會縮小result變數的類型,所以這種方法可能不完全符合你的需求。

    #

    回覆
    0
  • 取消回覆