Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

129
Vistas
Type return value when recursively re-mapping keys in object

I have a mapper which takes in any object, and if there is a key named 'fields' in it, it's replaced by its contents. So for example,

const obj = { x: 'hey', fields: { y: 'you' } }
const mapped = contentfulMapper(obj);

// mapped = { x: 'hey', y: 'you' }

Or

const givenObj = {
  a: "sdf",
  w: { 
    a2: 343,
    a3: true,
    fields: {
      a4: "ll",
      q: {
        fields: {
          a5: [2, 4, "lk"]
        }, 
      },
    },
  }, 
};
const mapped = contentfulMapper(givenObj);

/* mapped = {
  a: "sdf",
  w: { 
    a2: 343,
    a3: true,
    a4: "ll",
    q: {
      a5: [2, 4, "lk"]
    }, 
  }, 
}; */

Returning a Record<string, unknown> isn't great though, so my question is how can I type this correctly?

type TContentfulModel = {
  fields?: undefined | Record<string, TContentfulModel>;
};


const contentfulMapper = (
  obj: Record<string, TContentfulModel | unknown>
) => {
  let out: Record<string, unknown> = {};

  Object.keys(obj).forEach((key) => {
    const field = obj[key] as TContentfulModel;
    if (key === 'fields') {
      const mappedField = contentfulMapper(field);
      out = { ...out, ...mappedField };
      
    } else {
      out[key] =
        typeof obj[key] === 'object' && !Array.isArray(obj[key])
          ? contentfulMapper(field)
          : obj[key];
    }
  });

  return out;
};
about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

Here is a working solution. Please go through it, let me know if don't get anything. I will add any needed explanation, then.

type TContentfulModelExtended = {
  fields: TContentfulModelExtended | TContentfulModel
  [key: string]: any
}

type TContentfulModel = {
  [key: string]: any
}

// if `T` has `fields`, we omit that key, keep rest,
// and take it's intersection with the flatten nested fields
type Flat<T extends TContentfulModelExtended | TContentfulModel> = T extends TContentfulModelExtended
  ? Omit<T, 'fields'> & Flat<T['fields']>
  : T

type MyObjType = {
  a: string
  fields: {
    b: number
    c: boolean
    fields: {
      d: number[],
      fields: {
        e: Promise<number>
      }
    }
  }
}

type Flattened = Flat<MyObjType>

const obj: Flattened = {
  a: 'abc',
  b: 3,
  c: false,
  d: [3],
  e: Promise.resolve(3)
}


const contentfulMapper = <O extends TContentfulModelExtended | TContentfulModel>(obj: O) => {
  let out: Flat<O> = {} as any;

  Object.keys(obj).forEach((key) => {
    const field = obj[key];
    if (key === 'fields') {
    // @ts-ignore
      const mappedField = contentfulMapper(field);
      out = { ...out, ...mappedField };
      
    } else {
      out[key] =
        typeof obj[key] === 'object' && !Array.isArray(obj[key])
          ? contentfulMapper(field)
          : obj[key];
    }
  });

  // @ts-ignore
  return out;
};

const givenObj = {
  a: 'sdf',
  fields: {
    a2: 343,
    a3: true,
    fields: {
      a4: 'll',
      fields: {
        a5: [2, 4, 'lk']
      }
    }
  }
}

const objSpreaded = contentfulMapper(givenObj)
objSpreaded.a // all props from `a` to `e` works properly
objSpreaded.a2
objSpreaded.a3
objSpreaded.a4
objSpreaded.a5
objSpreaded.f // expected error

[Playground]

Please note, I have added compiler directive comments // @ts-ignore to get rid of infinite depth error.

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda