拥有一个可以包含任意数据的接口(例如通过库定义)并不罕见,如下所示:
interface Something {
name: string;
data: { [key: string]: any };
}
我遇到的问题是当我尝试访问或设置具有任意值的对象的值时,Typescript会出错。
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.bar
重写整个代码库到a.data['bar']
。
答案 0 :(得分:0)
如果您将类型定义为可索引,那么您需要访问如下属性:
a["data"].bar
您的游乐场示例:modified to work properly。
更多关于Indexable Types。
让我们从问题开始:
interface Something {
name: string;
data: { [key: string]: any };
}
在Something
界面中,有name
类型的特定属性名string
,因此编译器知道这意味着什么:
let a: Something = ...
console.log(a.name);
但是,如果我console.log(a["unknownKey"])
,那么它怎么知道这个unknownKey
是什么?它是对象中的有效属性吗?它是什么类型的?
编译器无法知道,因为您没有指定此对象具有此键,这就是您被迫使用索引表示法的原因。
如何解决这个问题?
好吧,您可以定义您知道的属性以及您已经在代码中使用的属性,例如,如果您使用属性name
,id
和address
,那么请在你的界面:
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);
这显然不是一个好的解决方案,但是如果你只是在将旧代码迁移到打字稿时会遇到摩擦,那么你可以使用它直到你想出一个更符合你需求的更好的解决方案。
答案 1 :(得分:0)
您的选择包括:
(a as any).data.bar
(a.data as any).bar
或者,您可以将Something
界面重新定义为
interface Something {
name: string;
data: any;
}
所有这些,是的,牺牲了一些类型检查。