Как предотвратить ошибку "подпись индекса типа объекта неявно имеет "любой" тип " при компиляции 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?

575   8  

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

    Ничего не найдено.