[英]Typescript error: Property [name] does not exist on Type [Object]
[英]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 錯誤。
const myObjectVariable: any = service.getObject();
this.anotherVariable = myObjectVariable.propertyName;
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#12501在TypeScript 2.2中引入。 那是在any
PR 完成之后。
換句話說:在何時從any
中縮小的邏輯被散列出來時,沒有object
類型需要考慮。 他們可能會將object
與Object
和Function
作為例外。 或者可能不是; 很難確定。 也許有人甚至可以在 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
一個更准確的類型,以表示您對它的實際了解。 例如,也許您知道它可以是string
、 number
或一些具有string
類型propertyName
屬性的 object 。 然后你會改用這個:
const myObjectVariable: string | number | { propertyName: string } = service.getObject();
if (_.isObject(myObjectVariable)) {
// {propertyName: string}
this.anotherVariable = myObjectVariable.propertyName; // okay
}
並且很高興編譯器刪除了string
和number
,並為您留下了 object 類型。 (這只是一個示例;您可以使用{ [k: string]: any } | undefined
代替...或其他類型的聯合,其中object
兼容的類型可以在propertyName
鍵處索引。)
如果你不能在你的代碼中這樣做,那么你不能,但這是我最強烈推薦的,因為它使用 TypeScript 的編譯器來幫助保持你的代碼類型安全,而不是尋找通過持久化來保持你的代碼不安全的方法any
.
無論如何,希望能解釋這種情況並為您提供一些選擇。 祝你好運!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.