Как получить упрощенный объект с помощью TS дженериков?
Все привет, помогите разобраться с дженериками в typescript. Есть вот такой объект, ключи имен group могут быть любыми, ключи имен variant тоже могут быть любыми:
const bigUser = {
group1: {
variant1: {
title: 'Egor',
age: 26,
},
variant2: {
title: 'Sasha',
age: 29,
}
},
group2: {
variant1: {
title: 'Ivan',
age: 33,
},
variant2: {
title: 'Igor',
age: 37,
}
}
};
Хочу на выходе получить вот такой объект
const miniUser = {
group1: {
variant1: 'Egor',
variant2: 'Sasha'
},
group2: {
variant1: 'Ivan',
variant2: 'Igor'
}
};
Описал вот такую функцию
function getNewObj<T extends object, K extends keyof T, U extends keyof K>(obj: T) {
const newUser: {[K in keyof T]?: {[U in keyof K]: string}} = {};
(Object.keys(obj) as K[]).forEach((groupKey) => {
newUser[groupKey] = {} as T[K];
if (obj[groupKey]) {
(Object.keys(obj[groupKey]) as U[]).forEach((key) => {
newUser[groupKey]['key'] = obj[groupKey][key].title as T[K][U];
})
}
})
return newUser;
}
Есть три проблемы, подскажите как их правильно решить
Как описать правильно title в (obj[groupKey][key].title) - Property 'title' does not exist on type 'T[K][U]'
newUser[groupKey]['key'] - Object is possibly 'undefined' и
newUser[groupKey]['key'] - Element implicitly has an 'any' type because expression of type '"key"' can't be used to index type '{ [U in keyof K]: string; }'. Property 'key' does not exist on type '{ [U in keyof K]: string; }'.
спасибо
Ответы (1 шт):
Ответы на вопросы
- Как описать правильно title в (obj[groupKey][key].title) - Property 'title' does not exist on type 'T[K][U]'
Ошибка говорит о том, что title
не существует для типа T[K][U]
. Ошибка возникает из-за того, что вы в качестве T
передаете "некий object", который может и не содержать на третьем уровне вложенности поле title
. Как исправить эту ошибку - дать obj
такой тип, чтобы typescript знал, что T[K][U] - это строгий тип, имеющий поля title: string
и age: number
.
- newUser[groupKey]['key'] - Object is possibly 'undefined
- newUser[groupKey]['key'] - Element implicitly has an 'any' type because expression of type '"key"' can't be used to index type '{ [U in keyof K]: string; }'. Property 'key' does not exist on type '{ [U in keyof K]: string; }'.
Здесь вы наверняка имели ввиду следующее: newUser[groupKey][key]
(без одинарных кавычек). Но даже решения для вышеперечисленных проблем не решают вашу задачу.
Решение
Все ваши проблемы решаются определением типов для User
, Group
и Variant
. Решение представлено ниже. Итоговая функция возвращает объект типа OutUser
, ключи которого тайпскрипт успешно распознает благодаря тому что эти ключи строятся из передаваемого в функцию obj: User
и его ключей G
и V
. Я позволил себе изменить обозначения для generic типов и имена переменных в функции. Сам код функции делает абсолютно тоже самое, что и делал до этого. Ссылка на TS Playground
type User<G extends string, V extends string> = {[groupKey in G]: Group<V>};
type Group<V extends string> = {[variantKey in V]: Variant};
type Variant = {
title: string;
age: number;
};
type OutUser<G extends string, V extends string> = {[groupKey in G]: OutGroup<V>};
type OutGroup<V extends string> = {[variantKey in V]: string};
function getNewObj<G extends string, V extends string>(obj: User<G, V>): OutUser<G, V> {
const newUser = {} as OutUser<G, V>;
(Object.keys(obj) as G[]).forEach((groupKey) => {
const group = obj[groupKey];
const newGroup = {} as OutGroup<V>;
newUser[groupKey] = newGroup;
if (group) {
(Object.keys(group) as V[]).forEach((variantKey) => {
newUser[groupKey][variantKey] = obj[groupKey][variantKey].title;
})
}
});
return newUser;
}
const bigUser = {
group1: {
variant1: {
title: 'Egor',
age: 26,
},
variant2: {
title: 'Sasha',
age: 29,
}
},
group2: {
variant1: {
title: 'Ivan',
age: 33,
},
variant2: {
title: 'Igor',
age: 37,
}
}
};
const smallUser = getNewObj(bigUser);
console.log(smallUser);
console.log('smallUser.group1.variant2', smallUser.group1.variant2);
Результат выполнения кода:
[LOG]: {
"group1": {
"variant1": "Egor",
"variant2": "Sasha"
},
"group2": {
"variant1": "Ivan",
"variant2": "Igor"
}
}
[LOG]: "smallUser.group1.variant2", "Sasha"