Dado el siguiente objeto:
{ __proxy: { state: { count: 0 items: { __proxy: { state: { amount: 0 } } } } } }Me gustaría convertirlo a:
{ count: 0, items: { amount: 0 } }Entonces, como puedes ver, estoy haciendo algunas cosas:
__proxy y mostrando su contenidostate y mostrar su contenidoHe intentado algo como el siguiente fragmento:
const removeKeys = (obj, keys) => obj !== Object(obj) ? obj : Array.isArray(obj) ? obj.map((item) => removeKeys(item, keys)) : Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k))); removeKeys(myObj, ['__proxy', 'state']) Sin embargo, elimina por completo __proxy y/o state , y quiero conservar su contenido.
Dicho esto, ¿conoces alguna solución existente para eso? ¿Una biblioteca de NPM, tal vez? ¿O una función lodash?
Nota: Como estoy usando TypeScript, sería preferible una solución escrita, pero js sin procesar tampoco funciona bien.
¡Gracias!
Podría desestructurar las propiedades no deseadas y subir el contenido un nivel.
const convert = ({ __proxy, state, ...object }) => __proxy || state ? convert({ ...(__proxy || {}), ...(state || {}), ...object }) : Object.fromEntries(Object .entries(object) .map(([k, v]) => [k, v && typeof v === 'object' ? convert(v) : v]) ) data = { __proxy: { state: { count: 0, items: { __proxy: { state: { amount: 0 } } } } } }, result = convert(data); console.log(result); .as-console-wrapper { max-height: 100% !important; top: 0; }Por lo general, para estos problemas empiezo con los tipos primero. A veces, hacer el tipo me da ideas sobre cómo implementarlo en el código, ¡así que aquí vamos!
Primero definamos un tipo que haga esto (lo llamo "obliteración" por el motivo que sea) solo para una clave:
type Obliterate<O, K> = O extends object ? { [P in Exclude<keyof O, K>]: Obliterate<O[P], K> } & (K extends keyof O ? Obliterate<O[K], K> : {}) : O; Si O no es un objeto, no hay nada que quitarle.
Sin embargo, si es así, se toman los siguientes pasos:
K de O y luego recorremos recursivamente el objeto y "borramos" todos los valores.K es una clave de O y si lo es lo cruzamos con el resultado del primer paso. Si no es así, lo cruzamos con {} que no hace nada. Luego, un tipo que toma una lista de claves, itera sobre ella y usa Obliterate en el objetivo:
type ObliterateEach<O, K> = K extends readonly [infer F, ...infer M] ? ObliterateEach<Obliterate<O, F>, M> : O; Si K no está vacío, operamos sobre el objeto; de lo contrario, terminamos y devolvemos el objeto.
Con estos tipos, he escrito mal el siguiente código que refleja cómo funcionan estos tipos:
const obliterate = <O, K extends PropertyKey>(o: O, k: K): Obliterate<O, K> => ( (o && typeof o === "object") ? Object.assign(Object.fromEntries(Object.entries(o).filter(([p]) => p !== k).map(([p, v]) => [p, obliterate(v, k)])), k in o ? obliterate((o as any)[k], k) : {}) : o ) as Obliterate<O, K>; const obliterateEach = <O, K extends ReadonlyArray<PropertyKey>>(o: O, k: K): ObliterateEach<O, K> => ( k.reduce<{}>((r, k) => obliterate(r, k), o) ) as ObliterateEach<O, K>;Puede leer estas funciones de la misma manera que los tipos anteriores. Son exactamente los mismos pasos, solo en código y no en tipos (y algunas conversiones para suprimir errores de tipo).
Ciertamente, esta no es la mejor solución fuertemente tipada, pero es un comienzo.
Un parque infantil que demuestra esta solución.