2016-07-26 68 views
0

的情況並不少見有一個接口(例如,通過庫定義),可以包含任意數據,這樣的:屬性訪問器maplike對象

interface Something { 
    name: string; 
    data: { [key: string]: any }; 
} 

我的問題是打字稿錯誤,當我嘗試訪問或者在具有任意值的對象上設置值。

let a: Something = { 
    name: 'foo', 
    data: { bar: 123 } 
}; 

// Below errors with: 'Property "bar" does not exist on type {[key:string]: any}' 
console.log(a.data.bar); 
a.data.bar = 234; 

這是一個在Typescript中的錯誤還是有一種簡單的方法來避免這樣的錯誤?

This Typescript playground清楚地說明了這個問題。

編輯

我正在尋找一個選項,希望不會讓我有整個代碼庫重寫從a.data.bara.data['bar']

回答

0

如果定義類型可轉位的,那麼你需要訪問像這樣的屬性:

a["data"].bar 

你的遊樂場例如:modified to work properly

更多關於Indexable Types


讓我們從問題開始:

interface Something { 
    name: string; 
    data: { [key: string]: any }; 
} 

在你Something接口有上string類型的特定屬性名name,所以編譯器知道這意味着什麼:

let a: Something = ... 
console.log(a.name); 

但,如果我做console.log(a["unknownKey"])那麼它怎麼知道這是什麼unknownKey?它是對象中的有效屬性嗎?它是什麼類型?
編譯器無法知道,因爲您尚未指定此對象具有此鍵,這就是您不得不使用索引表示法的原因。

如何解決此問題?
嗯,你可以定義你知道,在那裏,如果你使用的屬性,你已經在你的代碼中使用,例如性能nameidaddress然後讓這個在你的界面:

interface Something { 
    id: string; 
    name: string; 
    address: string; 
    data: { [key: string]: any }; 
} 

其他屬性可以保留爲索引。

您還可以使用類:

interface Something { 
    name: string; 
    data: { [key: string]: any }; 
} 

class MySomething { 
    public name: string; 
    public else: string; 

    constructor(obj: Something) { 
     this.name = obj.name; 
     this.else = obj["else"]; 
    } 
} 

當然另一種選擇是隻使用any它繞過編譯器的類型檢查:

let a: any = ... 
console.log(a.myProperty); 

這顯然不是一個很好的解決方案,但如果僅在與將舊代碼遷移到打字稿時產生摩擦的地方使用它,那麼您可以使用它,直到您找到適合您需求的更好的解決方案。

+0

感謝您的回覆,我以前見過這種方法,但對我來說似乎有缺陷。我正在嘗試將一個小型項目轉換爲Typescript,並且一個庫有一個類似於我的問題的界面。所以我需要去遍歷所有文件,並從首選的'obj.prop'轉換爲'obj ['prop']'? 此外,這個選項也讓我沒有代碼完成。這現在不是非常重要,但我覺得像這樣重寫我的代碼嚴重得多。 – Csvn

+0

@Csvn有沒有簡單的解決方案,但我編輯了我的答案,你有幾個選項。 –

+0

好吧,我似乎無法找到您提供的解決方案之外的解決方案。唯一的其他選擇似乎是將'{[key:string]:any}'改變/覆蓋到'any',這不太清楚。 – Csvn

0

選項包括:

(a as any).data.bar 
(a.data as any).bar 

或者,你可以重新定義Something接口爲

interface Something { 
    name: string; 
    data: any; 
} 

所有這些都做,是的,犧牲一些類型檢查。