Сделать типизацию для ключей объекта после flattenObject
Я не силен в TS настолько, чтобы реализовать такую типизацию, но уже долго мучаю GPT и не могу добиться нужного результата.
type FlattenObject<T> = T extends object
? T extends Array<any>
? T[ number ]
: {
[ K in keyof T ]: T[ K ] extends object
? FlattenObject<T[ K ]>
: T[ K ];
}
: T;
type FlattenRecord<T, Prefix extends string | number | symbol = ""> =
{
[ K in keyof T ]: T[ K ] extends object
? FlattenRecord<T[ K ], `${ Prefix & string }${ "" extends Prefix ? "" : "." }${ Extract<K, string & keyof T> & string }`>
: T[ K ];
};
export type Flatten<T> = FlattenObject<T> extends infer O ? FlattenRecord<O> : never;
function flattenObject<T extends object>(object: T, parentKey: string = ""): Flatten<T>
{
// @ts-ignore
return Object.keys(object).reduce<Flatten<T>>((acc: any, key: string) =>
{
const newKey = parentKey ? `${ parentKey }.${ key }` : key;
// @ts-ignore
if (typeof object[ key ] === "object" && object[ key ] !== null)
{
// @ts-ignore
const nestedObject = flattenObject(object[ key ], newKey);
Object.assign(acc, nestedObject);
}
else
{
// @ts-ignore
acc[ newKey ] = object[ key ];
}
return acc;
// @ts-ignore
}, {});
}
export default flattenObject;
На входе у нас объект который имеет интерфефс:
export interface IMember
{
_id: string;
avatar?: string;
name: Record<"ru" | "en", string>;
desc: Record<"ru" | "en", string>;
specialization: Record<"ru" | "en", string>;
}
То есть в теории после Flatten<IMember>
я должен получить тип:
{
_id: string;
avatar?: string;
name.ru: string;
name.en: string;
desc.ru: string;
desc.en: string;
specialization.ru: string;
specialization.en: string;
}
Ответы (1 шт):
Автор решения: Sdf
→ Ссылка
Необходимо определить тип Flatten, который будет отражать операцию "плоского" преобразования объекта. Этот тип должен корректно обрабатывать вложенные объекты и массивы, создавая из них тип с "плоскими" ключами.
type Primitive = string | number | boolean | bigint | symbol | undefined | null;
type Flatten<T> = T extends Primitive | Function | Date | Array<any> ? T : {
[K in keyof T as (T[K] extends object ? `${string & K}.${FlattenKeys<T[K]>}` : string & K)]: T[K] extends object ? Flatten<T[K]> : T[K]
}[keyof T];
type FlattenKeys<T> = T extends object ? {
[K in keyof T]: T[K] extends object ? `${string & K}.${FlattenKeys<T[K]>}` : string & K
}[keyof T] : '';
export type Flatten<T> = FlattenRecord<FlattenObject<T>>;
function flattenObject<T>(obj: T, prefix: string = ''): Flatten<T> {
let result: any = {};
for (const [key, value] of Object.entries(obj)) {
const flatKey = prefix ? `${prefix}.${key}` : key;
if (typeof value === 'object' && value !== null && !(value instanceof Date) && !(value instanceof Array) && !(value instanceof Function)) {
Object.assign(result, flattenObject(value, flatKey));
} else {
result[flatKey] = value;
}
}
return result;
}
Для примера:
const nestedObj = {
a: 1,
b: {
c: 2,
d: {
e: 3
}
}
};
const flatObj = flattenObject(nestedObj);
console.log(flatObj);