簡體   English   中英

Typescript 忽略顯式聲明的 ANY 類型並將變量視為類型 object 如果在變量上使用 _.isObject(),導致屬性名稱錯誤

[英]Typescript ignores explicitly stated ANY type and treats variable as type object if _.isObject() is used on the variable, causing property name errors

當我有一個類型為“any”的變量並對_.isObject 進行lodash 檢查,然后嘗試訪問該變量的屬性時,它會引發typescript 錯誤error TS2339: Property 'propertyName' does not exist on type 'object'.

我的期望是 typescript 繼續將變量視為:any因為這是明確聲明的,並且它允許訪問 object 上的任何屬性而不會引發 typescript 錯誤。


例子

沒有 object 檢查,沒有 typescript 錯誤:

const myObjectVariable: any = service.getObject();
this.anotherVariable = myObjectVariable.propertyName;

Object 檢查導致錯誤:

const myObjectVariable: any = service.getObject();
if (_.isObject(myObjectVariable) {
    this.anotherVariable = myObjectVariable.propertyName;
}

引發: error TS2339: Property 'propertyName' does not exist on type 'object'.

為什么在 typescript 忽略原始類型並將其視為 object 時會發生這種情況,我可以在不更改代碼的情況下將其關閉或使其停止嗎?

我認為這可能有點疏忽了如何縮小any范圍。 Lodash 的isObject()方法是一個用戶定義的類型保護,如果它返回true ,它會縮小它的參數,但這會以你不滿意的方式與any交互。


最初,當調用一個類型保護器,該類型保護器在類型為any的值上縮小到某些特定的 object 類型時,它根本不會縮小並保持any 這困擾了人們,因為編譯器應該能夠捕捉到這樣的錯誤:

interface Foo { x: string; }
declare function isFoo(x: any): x is Foo;
declare const v: any;

if (isFoo(v)) {
    v // still any
    v.x.toUperCase(); // no error?
}

這是在microsoft/TypeScript#9999中提出並在microsoft/TypeScript#10334中修復的。 所以現在人們得到了以下理想的行為:

if (isFoo(v)) {
    v // Foo
    v.x.toUperCase(); // error!
    // Property 'toUperCase' does not exist on type 'string'. Did you mean 'toUpperCase'?
}

any ,意圖都不是縮小范圍。 預期的邏輯在此注釋中表示:從any縮小到原語或特定 object 類型是可取的,但縮小到Object any Function是不可取的,因為這些類型幾乎沒有用。

因此,如果 lodash 的isObject()鍵入如下:

interface LoDashStatic {
    isObject(value?: any): value is Object; // Object 
}

那么你就不會有問題了:

if (_.isObject(myObjectVariable)) {
    // still any
    this.anotherVariable = myObjectVariable.propertyName; // okay
}

isObject()實際上是這樣聲明的:

interface LoDashStatic {
    isObject(value?: any): value is object; // lowercase o object 
}

那是使用object ,而不是Object object類型表示“非原始對象”,並通過microsoft/TypeScript#12501TypeScript 2.2中引入。 那是any PR 完成之后。

換句話說:在何時從any中縮小的邏輯被散列出來時,沒有object類型需要考慮。 他們可能會將objectObjectFunction作為例外。 或者可能不是; 很難確定。 也許有人甚至可以在 GitHub 中提出一個新問題,要求使用此處鏈接的問題作為理由來防止從any范圍縮小到object

但就目前而言,情況就是這樣, any范圍都縮小到object

if (_.isObject(myObjectVariable)) {
    // object
    this.anotherVariable = myObjectVariable.propertyName; // error!
}

那么作為一種解決方法,你能做些什么呢? 好吧,您始終可以通過聲明合並isObject()使用自己的自定義類型,該類型使用Object代替:

// merge into lodash typings
declare module 'lodash' {
    interface LoDashStatic {
        isObject(value?: any): value is Object; 
    }
}

或者您可以使用類型斷言“擴大”回any

this.anotherVariable = (myObjectVariable as any).propertyName; // error!

或者,由於any通常是有問題的類型,您可能希望給myObjectVariable一個更准確的類型,以表示您對它的實際了解。 例如,也許您知道它可以是stringnumber或一些具有string類型propertyName屬性的 object 。 然后你會改用這個:

const myObjectVariable: string | number | { propertyName: string } = service.getObject();
if (_.isObject(myObjectVariable)) {
    // {propertyName: string}
    this.anotherVariable = myObjectVariable.propertyName; // okay
}

並且很高興編譯器刪除了stringnumber ,並為您留下了 object 類型。 (這只是一個示例;您可以使用{ [k: string]: any } | undefined代替...或其他類型的聯合,其中object兼容的類型可以在propertyName鍵處索引。)

如果你不能在你的代碼中這樣做,那么你不能,但這是我最強烈推薦的,因為它使用 TypeScript 的編譯器來幫助保持你的代碼類型安全,而不是尋找通過持久化來保持你的代碼不安全的方法any .


無論如何,希望能解釋這種情況並為您提供一些選擇。 祝你好運!

游樂場鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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