Как предотвратить ошибку "подпись индекса типа объекта неявно имеет "любой" тип " при компиляции typescript с включенным флагом noImplicitAny?
Я всегда компилирую Typescript с флагом -- noImplicitAny. Это имеет смысл, поскольку я хочу, чтобы моя проверка типа была как можно более жесткой.
моя проблема заключается в том, что со следующим кодом я получаю ошибку 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?
8 ответов:
добавление подписи индекса позволит TypeScript знать, какой тип должен быть.
в вашем случае это будет
[key: string]: string;interface ISomeObject { firstKey: string; secondKey: string; thirdKey: string; [key: string]: string; }однако при этом также применяются все типы свойств, соответствующие сигнатуре индекса. Так как все свойства являются
stringэто работает.хотя подписи индекса являются мощным способом описания массива и шаблона "словарь", они также обеспечивают соответствие всех свойств их возвращению тип.
Edit:
если типы не совпадают, можно использовать тип объединения
[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;тогда вам нужно будет бросить типы, как вы сделали выше.
другой способ избежать ошибки-использовать приведение следующим образом:
let secondValue: string = (<any>someObject)[key];(обратите внимание на скобки)единственная проблема заключается в том, что это больше не типобезопасно, так как вы бросаете в
any. Но вы всегда можете вернуться к правильному типу.ps: я использую typescript 1.7, не уверен в предыдущих версиях.
следующее настройка tsconfig позволит вам игнорировать эти ошибки - установите в значение true.
suppressImplicitAnyIndexErrors
подавить ошибки noImplicitAny для индексирования объектов, не имеющих подписи индекса.
TypeScript 2.1 представил элегантный способ справиться с этой проблемой.
const key: (keyof ISomeObject) = 'secondKey'; const secondValue: string = someObject[key];мы можем получить доступ ко всем именам свойств объекта на этапе компиляции с помощью
keyofключевое слово (см. список изменений).вам нужно только заменить
stringтип переменной сkeyof ISomeObject. Теперь компилятор знаетkeyпеременная может содержать только имена свойств из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 (set )
Читать далее с больше
keyofобычаи.
объявите объект следующим образом.
export interface Thread { id:number; messageIds: number[]; participants: { [key:number]: number }; }
похоже на ответ @Piotr Lewandowski, но в пределах
forEach:const config: MyConfig = { ... }; Object.keys(config) .forEach((key: keyof MyConfig) => { if (config[key]) { // ... } });
решение "keyof", упомянутое выше, работает. Но если переменная используется только один раз, например, цикл через объект и т. д., Вы также можете ее типизировать.
for (const key in someObject) { sampleObject[key] = someObject[key as keyof ISomeObject]; }
на сегодняшний день лучшим решением является объявление типов. Как
enum SomeObjectKeys { firstKey = 'firstKey', secondKey = 'secondKey', thirdKey = 'thirdKey', } let someObject: Record<SomeObjectKeys, string> = { firstKey: 'firstValue', secondKey: 'secondValue', thirdKey: 'thirdValue', }; let key: SomeObjectKeys = 'secondKey'; let secondValue: string = someObject[key];
Comments