Estoy tratando de recuperar las claves de un objeto anidado dinámicamente. Un ejemplo del objeto que puedo tener:
{ ts: "2021-05-06T11:06:18Z", pr: 94665, pm25: 5, co2: 1605, hm: 32, m: { isConnected: true, wifidBm: 0, }, pm1: 5, s: { "0": { runningTime: 0, sn: "05064906137109790000", wearRate: 0, enabled: true, co2: 1605, }, "1": { enabled: false, sn: "125630092251006", }, "2": { enabled: false, sn: "05064906137109450000", }, "3": { fanStatus: 0, pm25: 5, pm1: "5", e: { rawSensorError: 0, }, pm10: 5, runningTime: 0, sn: "125630100924141", wearRate: 0, enabled: true, }, }, id: "avo_jggv6bsf211", tp: "20.6", pm10: 5, type: "monitor", }Por ejemplo, necesitaré tener:
str = 'ts, pr, pm25, co2, hm, "m.isConnected, m. wifiBm, pm1, s.0.runningTime, s.0.sn, ...'y ese es mi código por ahora:
guessHeader(object: MeasurementModel | any, parentKey?: string): string[] { // Looping on object's keys Object.keys(object).forEach(key => { if (typeof object[key] === 'object' && key !== 'ts') { // If the object is an array recurse in it return this.guessHeader(object[key], key) } else { // If we have a parentKey keep header as if (parentKey) this.header.push(`${parentKey}.${key}`) else this.header.push(key) } }) return this.header }Funciona para la clave m, tengo m.isConnected y m.wifiBm pero para s.0.runningTime solo tengo 0.runningTime. Además, este objeto puede cambiar y anidarse aún más. Necesito encontrar una manera que funcione para cualquier caso. Intenté guardar las claves en una matriz y luego analizarlas, pero fallé.
El problema está aquí:
// If the object is an array recurse in it return this.guessHeader(object[key], key)Esto debería ser
this.header.push(...this.guessHeader(object[key], parentKey === undefined ? key : `${parentKey}.${key}`)) Además, typeof null === 'object' , por lo que también debe verificar si ese object[key] no es nulo (por ejemplo, typeof object[key] === 'object' && object[key] ) antes de pasarlo a guessHeader .
Otra cosa es que MeasurementModel | any es lo mismo que any . Evite usar any y use unknown en su lugar , que es de tipo seguro.
Una implementación de guessHeader podría verse así:
guessHeader(object: object, parentKey?: string): string[] { Object.keys(object).forEach(key => { const newKey = parentKey === undefined ? key : `${parentKey}.${key}` const value = (object as Record<string, unknown>)[key] if (typeof value === 'object' && value && key !== 'ts') this.header.push(...this.guessHeader(value, newKey)) else this.header.push(newKey) }) return this.header } Personalmente, usaría Object.entries y haría algo como esto:
const guessHeader = (object: object, acc = ''): string => Object.entries(object) .map(([key, value]: [string, unknown]) => // It looks like you don't want to recurse into the ts key, // which is why I used key !== 'ts' // I'm guessing ts might be a Date; you could avoid recursing into // all Dates by doing // typeof value == 'object' && value && !(value instanceof Date) key !== 'ts' && typeof value === 'object' && value ? guessHeader(value, `${acc}${key}.`) : acc + key ) .join(', ') const input = {ts: '2021-05-06T11:06:18Z', pr: 94665, pm25: 5, co2: 1605, hm: 32, m: {isConnected: true, wifidBm: 0}, pm1: 5, s: {0: {runningTime: 0, sn: '05064906137109790000', wearRate: 0, enabled: true, co2: 1605}, 1: {enabled: false, sn: '125630092251006'}, 2: {enabled: false, sn: '05064906137109450000'}, 3: {fanStatus: 0, pm25: 5, pm1: '5', e: {rawSensorError: 0}, pm10: 5, runningTime: 0, sn: '125630100924141', wearRate: 0, enabled: true}}, id: 'avo_jggv6bsf211', tp: '20.6', pm10: 5, type: 'monitor'} // same as above code block const guessHeader = (object, acc = '') => Object.entries(object).map(([key, value]) => key !== 'ts' && typeof value === 'object' && value ? guessHeader(value, `${acc}${key}.`) : acc + key).join(', ') console.log(guessHeader(input))