2016-07-26 69 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; 
} 

所有这些都做,是的,牺牲一些类型检查。