Búsqueda de sitios web

Typescript: cambiar el tipo de las propiedades de un objeto y de las propiedades de objetos anidados a un solo tipo


Teniendo este ejemplo:

interface Event {
  title:string;
  description:string;
  fromDate: Date;
  toDate: Date;
  location: {
    name: string;
    lat: number;
    long: number;
  }
}

Usando un tipo algo como PropertiesToString<Event> espero devolver este tipo:

{
  title:string;
  description:string;
  fromDate: string;
  toDate: string;
  location: {
    name: string;
    lat: string;
    long: string;
  }
}

La pregunta es ¿cómo creo el tipo PropertiesToString<T>?

He logrado crear algo que funciona, pero no para objetos anidados. Si tengo un objeto anidado, en lugar de modificar las propiedades del objeto a cadena, establece el objeto como cadena.

Esta es mi versión que no funciona para objetos anidados, porque en lugar de cambiar el tipo de propiedades de location a string, cambia el tipo de location en sí a string:

export type RequestBody<T> = {
  [P in keyof T]: string;
};

Respuesta #1

el tipo ToString convierte un tipo dado a string. PropertiesToString itera sobre cada clave del tipo pasado y cambia su tipo a string usando ToString. Puedes agregar otros casos especiales que quieras manejar en ToString usando el operador ternario de tipos.

interface Event1 {
    title: string;
    description: string;
    fromDate: Date;
    toDate: Date;
    location: {
        name: string;
        lat: number;
        long: number;
  }
}

type ToString<T> = T extends Date
    ? string
    : T extends object
    ? PropertiesToString<T>
    : string

type PropertiesToString<T> = {
    [K in keyof T]: ToString<T[K]>
}

type Generated = PropertiesToString<Event1>

type X = PropertiesToString<Event1['location']>

const x: Generated = {
    title: 'lorem',
    description: 'lorem',
    fromDate: 'lorem',
    toDate: 'lorem',
    location: {
        name: 'lorem',
        lat: 'lorem',
        long: 'lorem',
    }
}

Parque infantil

Respuesta #2

En realidad estás muy cerca. Sin embargo, habrá algunos casos límite que probablemente tendrás que manejar. En JS muchas cosas son objetos, y probablemente no querrás que todos ellos simplemente se conviertan en cadenas. Así que probablemente tendrás que mejorar esto con un poco más de lógica. Pero en su forma más simple

type RecursiveObject<T> = T extends Date ? never : T extends object ? T : never; 
export type StringValues<TModel> = {
    [Key in keyof TModel]: TModel[Key] extends RecursiveObject<TModel[Key]> ? StringValues<TModel[Key]> : string;
};

Agrega cualquier caso especial (¿Array? ¿Otros tipos envolventes?) que necesites manejar en tu código. Eventualmente obtendremos el manejo de "not" en los tipos, y esto será mucho más sencillo.

Artículos relacionados