Как установить подпись индекса без открытия интерфейса - PullRequest
0 голосов
/ 26 июня 2018

Рассмотрим этот код:

interface MyInterface {
  foo: string
  bar: string
  baz: string
}

const myObj: MyInterface = {
  foo: "foo",
  bar: "bar",
  baz: "baz"
};

Object.keys(myObj).forEach(obj => {
  obj = myObj[obj];
});

При включении строгого режима я получаю эту ошибку: TS7017: Элемент неявно имеет тип 'any', потому что тип 'MyInterface' не имеет подписи индекса.

Кажется, самое простое решение:

interface MyInterface {
  [key: string]: string;
  foo: string
  bar: string
  baz: string
}

однако это открывается для любых строковых свойств в объектах MyInterface.

Тогда я подумал об использовании сопоставленного типа:

type ValidEnteries = "foo" | "bar" | "baz";

type Alternative = {
  [key in ValidEnteries]: string
}

Хотя мне это кажется правильным, исходная проблема возвращается с отсутствующей подписью индекса.

Можно ли как-то иметь подпись индекса и ограничить объект определенным количеством свойств?

1 Ответ

0 голосов
/ 26 июня 2018

Если все, что вы хотите сделать, это получить уже существующие свойства интерфейса, вам не нужна подпись индекса.Вы можете индексировать любой объект с помощью строки, если строка является известным ключом объекта.Так что это работает:

 myObj['bar'] // 'bar' can be checked as a key of MyInterface so it's ok 

Проблема в том, что Object.keys(myObj) возвращает string[], а не Array<keyof T>.Самое простое решение - использовать утверждение типа, чтобы сообщить компилятору, что возвращаемое значение keys является массивом ключей MyInterface

Object.keys(myObj).forEach(obj => {
    let d = myObj[obj as keyof MyInterface];
});
// OR
(Object.keys(myObj) as Array<keyof MyInterface>).forEach(obj => {
    let d = myObj[obj];
});

, или если вам удобна функция keys всегдавернув Array<keyof T> вы можете расширить глобальную декларацию

declare global { /// Needed if you are in a module otherwise omit this and the closing }
    interface ObjectConstructor {
        keys<T extends object>(o: T) : Array<keyof T>
    }
}

// Now works without any extra casting 
Object.keys(myObj).forEach(obj => {
    let d = myObj[obj];
}); 
...