我总是用noImplicitAny标记编译TypeScript。这是有意义的,因为我希望我的类型检查尽可能严格。

我的问题是,下面的代码我得到的错误:

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];

需要注意的是,这里的思想是键变量来自应用程序中的其他地方,可以是对象中的任何键。

我已经尝试通过以下方式显式地转换类型:

let secondValue: string = <string>someObject[key];

或者我的场景只是不可能与-noImplicitAny?


当前回答

上面提到的“keyof”解决方案是有效的。但如果变量只使用一次,例如循环遍历一个对象等,你也可以对它进行类型转换。

for (const key in someObject) {
    sampleObject[key] = someObject[key as keyof ISomeObject];
}

其他回答

创建一个接口来定义'indexer'接口

然后用该索引创建对象。

注意:这仍然会有其他答案所描述的关于强制每个项目的类型的相同问题-但这通常正是你想要的。

您可以根据需要设置泛型类型参数: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];

打印稿操场


你甚至可以在定义泛型类型时在泛型约束中使用this:

导出类SmartFormGroup<T extends IndexableObject<any>> extends FormGroup

然后类中的T可以被索引:-)

导致

你只能在索引时使用类型,这意味着你不能使用const来进行变量引用:

例子

type Person = { age: number; name: string; alive: boolean };

const key = "age";
type Age = Person[key];

结果

Type 'any' cannot be used as an index type.

解决方案

使用类型来引用道具

例子

type key = "age";
type Age = Person[key];

结果

type Age = number

像这样声明对象。

export interface Thread {
    id:number;
    messageIds: number[];
    participants: {
        [key:number]: number
    };
}

没有索引器?那就自己做吧!

我将其全局定义为定义对象签名的一种简单方法。如果需要,T可以是任何:

type Indexer<T> = { [ key: string ]: T };

我只是将indexer添加为类成员。

indexer = this as unknown as Indexer<Fruit>;

所以我的结论是:

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

这样做的好处是您可以得到正确的类型—许多使用<any>的解决方案将为您丢失输入。记住,这不会执行任何运行时验证。如果您不确定某个东西是否存在,您仍然需要检查它是否存在。

如果你想过于谨慎,并且你正在使用strict,你可以这样做来揭示所有你可能需要进行显式未定义检查的地方:

type OptionalIndexed<T> = { [ key: string ]: T | undefined };

我通常不认为这是必要的,因为如果我有来自某处的字符串属性,我通常知道它是有效的。

我发现,如果我有很多代码需要访问索引器,并且可以在一个地方更改类型,那么这个方法特别有用。

注意:我使用的是严格模式,未知是绝对必要的。

编译后的代码将是indexer = this,这与typescript为你创建_this = this非常相似。

使用typeof键

const cat = {
    name: 'tuntun'
}

const key: string = 'name' 

cat[key as keyof typeof cat]