我总是用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?


当前回答

我能在3个步骤中使用Typescript 3.1找到的最简单的解决方案是:

1)制作界面

interface IOriginal {
    original: { [key: string]: any }
}

2)打印一份

let copy: IOriginal = (original as any)[key];

3)在任何地方使用(包括JSX)

<input customProp={copy} />

其他回答

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

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

像这样声明对象。

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

创建一个接口来定义'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可以被索引:-)

添加索引签名将让TypeScript知道应该是什么类型。

在你的例子中,这将是[key: string]: string;

interface ISomeObject {
    firstKey:      string;
    secondKey:     string;
    thirdKey:      string;
    [key: string]: string;
}

但是,这也强制所有属性类型与索引签名匹配。因为所有的属性都是一个字符串,所以它可以工作。

虽然索引签名是描述数组和“字典”模式的强大方法,但它们也强制所有属性匹配它们的返回类型。

编辑:

如果类型不匹配,则可以使用联合类型[key: string]: string|IOtherObject;

对于联合类型,最好让TypeScript推断类型,而不是定义类型。

// Type of `secondValue` is `string|IOtherObject`
let secondValue = someObject[key];
// Type of `foo` is `string`
let foo = secondValue + '';

尽管如果索引签名中有很多不同的类型,这可能会有点混乱。另一种方法是在签名中使用any。[key: string]: any;然后需要像上面那样强制转换类型。

TypeScript 2.1引入了优雅的方法来处理这个问题。

const key: (keyof ISomeObject) = 'secondKey';
const secondValue: string = someObject[key];

我们可以在编译阶段通过keyof关键字(参见changelog)访问所有对象属性名。

你只需要用keyof ISomeObject替换字符串变量类型。 现在编译器知道关键变量只允许包含来自ISomeObject的属性名。

完整的例子:

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

typescriptlang.org上的实时代码(设置noImplicitAny选项)

进一步阅读,了解更多用法要点。