Несмотря на то, что ключи объектов всегда являются строками под капотом, а ввод индексаторов в виде строк охватывает числа, иногда вам нужно, чтобы функция знала о ключах объектов, которые ей передаются. Рассмотрим эту функцию сопоставления, которая работает как Array.map
, но с объектами:
function map<T>(obj: Object, callback: (key: string, value: any) => T): T[] {
// ...
}
key
может быть только string
, а значение полностью нетипизировано. Наверное, хорошо в 9 случаях из 10, но мы можем добиться большего. Допустим, мы хотели сделать что-то вроде этой глупости:
const obj: {[key: number]: string} = { 1: "hello", 2: "world", 3: "foo", 4: "bar" };
map(obj, (key, value) => `${key / 2} ${value}`);
// error: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.
Мы не можем выполнять какие-либо арифметические операции с ключом без предварительного преобразования его в число (помните: "3" / 2
допустимо в JS и разрешается в number
). Мы можем обойти это с помощью небольшого количества сложного набора текста в нашей функции карты:
function map<S, T>(obj: S, callback: (key: keyof S, value: S[keyof S]) => T): T[] {
return Object.keys(obj).map(key => callback(key as any, (obj as any)[key]));
}
Здесь мы используем общий S
для ввода нашего объекта и поиска типов ключей и значений непосредственно из него. Если ваш объект типизирован с использованием общих индексаторов и значений, keyof S
и S[keyof S]
будут преобразованы в постоянные типы. Если вы передадите объект с явными свойствами, keyof S
будет ограничен именами свойств, а S[keyof S]
будет ограничен типами значений свойств.
person
Sandy Gifford
schedule
05.02.2018