#typescript #generics
#typescript #общие
Вопрос:
У меня есть функция, которая принимает объект с дочерним массивом того же типа. Теперь я хочу преобразовать список дочерних элементов в объект, индексируемый идентификатором дочерних элементов.
Я хотел бы смоделировать это в Typescript и выполнить следующее:
export const convertHierarchyToDiffFriendly = <T extends {id: string, children?: T[]}, U extends T amp; {children: {[id: string]: U}}>(x: T): U => (<U>{
...x,
children: x.children ?
<U["children"]>x.children.reduce((z, y) => ({
...z,
[y.id]: convertHierarchyToDiffFriendly(y)}),
<{[id: string]: U}>{}) : {}
})
Это работает, но:
const convertedRhs = convertHierarchyToDiffFriendly(<IVendorStatusInput>rhs)
const c = convertedRhs.children["10"] // c's type is {}, not T amp; {children: {[id]: U}}
Отчасти очевидно, что U не будет выведен правильно, но как это могло быть?
Ответ №1:
Я не думаю, что вы хотите U
быть универсальным. Вместо этого вы хотите, чтобы это была функция T
типа, использующая отображенные и условные типы, что-то вроде этого:
type ConvertToDiffFriendly<T extends { id: string, children?: T[] }> = {
[K in keyof T]: "children" extends K ? { [id: string]: ConvertToDiffFriendly<T> } : T[K]
};
Таким образом, ConvertToDiffFriendly<T>
это то же самое, что и T
за исключением того, что его children
свойство (если оно у него есть) изменено в type. Теперь вы можете ввести свою функцию следующим образом:
export const convertHierarchyToDiffFriendly = <T extends { id: string, children?: T[] }>(
x: T
): ConvertToDiffFriendly<T> => ({
...x,
children: x.children ?
x.children.reduce((z, y) => ({
...z,
[y.id]: convertHierarchyToDiffFriendly(y)
}),
<{ [id: string]: ConvertToDiffFriendly<T> }>{}) : {}
} as ConvertToDiffFriendly<T>)
Я не проверял реализацию на правильность, но типизации должны быть разумными.
Наконец, давайте протестируем это:
interface IVendorStatusThingy {
id: string,
children: IVendorStatusThingy[],
limbs: number,
withCheese: boolean
}
declare const rhs: IVendorStatusThingy;
const convertedRhs = convertHierarchyToDiffFriendly(rhs)
const c = convertedRhs.children["10"]
// c's type is ConvertToDiffFriendly<IVendorStatusThingy>
На мой взгляд, выглядит неплохо. Надеюсь, это поможет; удачи!
Комментарии:
1. Вы правы — это, должно быть, правильный путь. Спасибо!