typescript 在启用 noImplicitAny 标志的情况下编译打字稿时,如何防止出现错误“对象类型的索引签名隐式具有‘任何’类型”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32968332/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I prevent the error "Index signature of object type implicitly has an 'any' type" when compiling typescript with noImplicitAny flag enabled?
提问by Jasper Schulte
I always compile Typescript with the flag --noImplicitAny. This makes sense as I want my type checking to be as tight as possible.
我总是用 --noImplicitAny 标志编译 Typescript。这是有道理的,因为我希望我的类型检查尽可能严格。
My problem is that with the following code I get the error Index signature of object type implicitly has an 'any' type
:
我的问题是使用以下代码时出现错误Index signature of object type implicitly has an 'any' type
:
interface ISomeObject {
firstKey: string;
secondKey: string;
thirdKey: string;
}
let someObject: ISomeObject = {
firstKey: 'firstValue',
secondKey: 'secondValue',
thirdKey: 'thirdValue'
};
let key: string = 'secondKey';
let secondValue: string = someObject[key];
Important to note is that the idea is that the key variable comes from somewhere else in the application and can be any of the keys in the object.
需要注意的重要一点是,这个想法是键变量来自应用程序中的其他地方,并且可以是对象中的任何键。
I've tried explicitly casting the type by:
我已经尝试通过以下方式显式转换类型:
let secondValue: string = <string>someObject[key];
Or is my scenario just not possible with --noImplicitAny
?
或者我的场景是不可能的--noImplicitAny
?
回答by thoughtrepo
Adding an index signature will let TypeScript know what the type should be.
添加索引签名会让 TypeScript 知道类型应该是什么。
In your case that would be [key: string]: string;
在你的情况下,这将是 [key: string]: string;
interface ISomeObject {
firstKey: string;
secondKey: string;
thirdKey: string;
[key: string]: string;
}
However, this also enforces all of the property types to match the index signature. Since all of the properties are a string
it works.
但是,这也会强制所有属性类型匹配索引签名。由于所有属性都是 astring
它有效。
While index signatures are a powerful way to describe the array and 'dictionary' pattern, they also enforce that all properties match their return type.
虽然索引签名是一种描述数组和“字典”模式的强大方式,但它们也强制所有属性匹配它们的返回类型。
Edit:
编辑:
If the types don't match, a union type can be used [key: string]: string|IOtherObject;
如果类型不匹配,可以使用联合类型 [key: string]: string|IOtherObject;
With union types, it's better if you let TypeScript infer the type instead of defining it.
对于联合类型,最好让 TypeScript 推断类型而不是定义类型。
// Type of `secondValue` is `string|IOtherObject`
let secondValue = someObject[key];
// Type of `foo` is `string`
let foo = secondValue + '';
Although that can get a little messy if you have a lot of different types in the index signatures. The alternative to that is to use any
in the signature. [key: string]: any;
Then you would need to cast the types like you did above.
尽管如果索引签名中有很多不同的类型,这可能会有点混乱。另一种方法是any
在签名中使用。[key: string]: any;
然后你需要像上面那样转换类型。
回答by Pedro Villa Verde
Another way to avoid the error is to use the cast like this:
避免错误的另一种方法是使用这样的演员表:
let secondValue: string = (<any>someObject)[key];
(Note the parenthesis)
let secondValue: string = (<any>someObject)[key];
(注意括号)
The only problem is that this isn't type-safe anymore, as you are casting to any
. But you can always cast back to the correct type.
唯一的问题是这不再是类型安全的,因为您正在转换为any
. 但是你总是可以转换回正确的类型。
ps: I'm using typescript 1.7, not sure about previous versions.
ps:我使用的是 typescript 1.7,不确定以前的版本。
回答by Piotr Lewandowski
TypeScript 2.1introduced elegant way to handle this issue.
TypeScript 2.1引入了优雅的方式来处理这个问题。
const key: (keyof ISomeObject) = 'secondKey';
const secondValue: string = someObject[key];
We can access all object property names during compilation phase by keyof
keyword (see changelog).
我们可以在编译阶段通过keyof
关键字访问所有对象属性名称(请参阅更改日志)。
You only need to replace string
variable type with keyof ISomeObject
.
Now compiler knows key
variable is allowed to contain only property names from ISomeObject
.
您只需要将string
变量类型替换为keyof ISomeObject
. 现在编译器知道key
变量只允许包含来自ISomeObject
.
Full example:
完整示例:
interface ISomeObject {
firstKey: string;
secondKey: string;
thirdKey: number;
}
const someObject: ISomeObject = {
firstKey: 'firstValue',
secondKey: 'secondValue',
thirdKey: 3
};
const key: (keyof ISomeObject) = 'secondKey';
const secondValue: string = someObject[key];
// You can mix types in interface, keyof will know which types you refer to.
const keyNumber: (keyof ISomeObject) = 'thirdKey';
const numberValue: number = someObject[keyNumber];
Live code on typescriptlang.org(set noImplicitAny
option)
typescriptlang.org上的实时代码(设置noImplicitAny
选项)
Further reading with more keyof
usages.
进一步阅读更多keyof
用法。
回答by Scott Munro
The following tsconfig settingwill allow you to ignore these errors - set it to true.
以下tsconfig 设置将允许您忽略这些错误 - 将其设置为 true。
suppressImplicitAnyIndexErrors
Suppress noImplicitAny errors for indexing objects lacking index signatures.
抑制ImplicitAnyIndexErrors
抑制没有索引签名的索引对象的 noImplicitAny 错误。
回答by Karna
The 'keyof' solution mentioned above works. But if the variable is used only once e.g looping through an object etc, you can also typecast it.
上面提到的“keyof”解决方案有效。但是如果变量只使用一次,例如循环对象等,你也可以对它进行类型转换。
for (const key in someObject) {
sampleObject[key] = someObject[key as keyof ISomeObject];
}
回答by alsotang
use keyof typeof
用 keyof typeof
const cat = {
name: 'tuntun'
}
const key: string = 'name'
cat[key as keyof typeof cat]
回答by Steve Brush
Similar to @Piotr Lewandowski's answer, but within a forEach
:
类似于@Piotr Lewandowski 的回答,但在一个范围内forEach
:
const config: MyConfig = { ... };
Object.keys(config)
.forEach((key: keyof MyConfig) => {
if (config[key]) {
// ...
}
});
回答by Supun Dharmarathne
Declare the object like this.
像这样声明对象。
export interface Thread {
id:number;
messageIds: number[];
participants: {
[key:number]: number
};
}
回答by Simon_Weaver
No indexer? Then make your own!
没有索引器?那就自己做吧!
I've globally defined this as an easy way to define an object signature. T
can be any
if needed:
我已将其全局定义为定义对象签名的简单方法。T
可any
如果需要的话:
type Indexer<T> = { [ key: string ]: T };
I just add indexer
as a class member.
我只是添加indexer
为班级成员。
indexer = this as unknown as Indexer<Fruit>;
So I end up with this:
所以我最终得到了这个:
constructor(private breakpointResponsiveService: FeatureBoxBreakpointResponsiveService) {
}
apple: Fruit<string>;
pear: Fruit<string>;
// just a reference to 'this' at runtime
indexer = this as unknown as Indexer<Fruit>;
something() {
this.indexer['apple'] = ... // typed as Fruit
Benefit of doing this is that you get the proper type back - many solutions that use <any>
will lose the typing for you. Remember this doesn't perform any runtime verification. You'll still need to check if something exists if you don't know for sure it exists.
这样做的好处是您可以获得正确的类型 - 许多使用的解决方案<any>
都会为您丢失类型。请记住,这不会执行任何运行时验证。如果你不确定它是否存在,你仍然需要检查它是否存在。
If you want to be overly cautious, and you're using strict
you can do this to reveal all the places you may need to do an explicit undefined check:
如果您想过于谨慎,并且您正在使用,strict
您可以这样做以显示您可能需要进行显式未定义检查的所有位置:
type OptionalIndexed<T> = { [ key: string ]: T | undefined };
I don't usually find this necessary since if I have as a string property from somewhere I usually know that it's valid.
我通常不认为这是必要的,因为如果我从某个地方作为字符串属性,我通常知道它是有效的。
I've found this method especially useful if I have a lot of code that needs to access the indexer, and the typing can be changed in just one place.
我发现如果我有很多代码需要访问索引器,并且可以在一个地方更改类型,则此方法特别有用。
Note: I'm using strict
mode, and the unknown
is definitely necessary.
注意:我正在使用strict
模式,而且unknown
绝对是必要的。
The compiled code will just be indexer = this
, so it's very similar to when typescript creates _this = this
for you.
编译后的代码将只是indexer = this
,因此它与打字稿_this = this
为您创建时非常相似。
回答by Simon_Weaver
Create an interface to define the 'indexer' interface
创建一个接口来定义“索引器”接口
Then create your object with that index.
然后使用该索引创建您的对象。
Note:this will still have same issues other answers have described with respect to enforcing the type of each item - but that's often exactly what you want.
注意:这仍然会有其他答案在强制执行每个项目的类型方面描述的相同问题 - 但这通常正是您想要的。
You can make the generic type parameter whatever you need : ObjectIndexer< Dog | Cat>
您可以根据需要制作泛型类型参数: ObjectIndexer< Dog | Cat>
// this should be global somewhere, or you may already be
// using a library that provides such a type
export interface ObjectIndexer<T> {
[id: string]: T;
}
interface ISomeObject extends ObjectIndexer<string>
{
firstKey: string;
secondKey: string;
thirdKey: string;
}
let someObject: ISomeObject = {
firstKey: 'firstValue',
secondKey: 'secondValue',
thirdKey: 'thirdValue'
};
let key: string = 'secondKey';
let secondValue: string = someObject[key];
You can even use this in a generic constraintwhen defining a generic type:
在定义泛型类型时,您甚至可以在泛型约束中使用它:
export class SmartFormGroup<T extends IndexableObject<any>> extends FormGroup
export class SmartFormGroup<T extends IndexableObject<any>> extends FormGroup
Then T
inside the class can be indexed :-)
然后T
可以在类内部建立索引:-)