reactjs - Convertir fechas correctamente desde una respuesta de API en typescript
Tengo una API REST que proporciona datos en el siguiente formato:-
{"id": 1, "name": "New event", "date": "2020-11-14T18:02:00"}Y una interfaz en mi aplicación frontend de React así:-
export interface MyEvent {
id: number;
name: string;
date: Date;
}
Uso axios para obtener la respuesta de la API.
const response = await axios.get<MyEvent>("/event/1");
const data = response.data;
Sin embargo, data.date sigue siendo una cadena debido a las limitaciones de TypeScript.
Esto puede causar problemas más adelante en el código, donde espero que todos esos campos de fecha sean un objeto Date real.
Probablemente podría hacer algo como: data.date=new Date(data.date);. Pero ese no sería un enfoque factible por muchas razones.
¿Existe una mejor manera de manejar fechas en TypeScript? ¿Cómo manejas generalmente las fechas que vienen de la respuesta de una API?
Respuesta #1
Actualizar
Ahora que Zod tiene la opción coerce, creo que es un mejor enfoque usarla para validar y analizar tu respuesta de API entrante.
Puedes usarlo así:-
const eventSchema = z.object({
number: z.number(),
name: z.string(),
date: z.coerce.date()
});
const myEvent = eventSchema.parse(response.data);
También puedes crear un tipo a partir de eventSchema para usarlo en todo tu código:
type MyEvent = z.infer<typeof eventSchema>
Solución Antigua
Entonces, la solución que mejor se adapta a mi caso de uso es similar a la mencionada por @Amy en el comentario de la pregunta original.
Así que uso interceptores de Axios para convertir las fechas en un objeto Date.
const client = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_BASE_URL });
client.interceptors.response.use(originalResponse => {
handleDates(originalResponse.data);
return originalResponse;
});
export default client;
Para identificar fechas, he usado una expresión regex, y para la conversión a objeto Date, he usado el paquete date-fns.
const isoDateFormat = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d*)?$/;
function isIsoDateString(value: any): boolean {
return value && typeof value === "string" && isoDateFormat.test(value);
}
export function handleDates(body: any) {
if (body === null || body === undefined || typeof body !== "object")
return body;
for (const key of Object.keys(body)) {
const value = body[key];
if (isIsoDateString(value)) body[key] = parseISO(value);
else if (typeof value === "object") handleDates(value);
}
}
Respuesta #2
Este tema merece mucha más atención de la que recibe. Para mí, la cordura depende de que todas las fechas en json se conviertan automáticamente en objetos de fecha en el momento en que aparecen en mi aplicación. La mejor manera de hacer esto es modificar el objeto JSON global. Esto es, obviamente, un cambio fundamental a una API global muy usada, pero es un cambio para mejor. Funciona con Axios, sin interceptores, y también funcionará si algún genio decide usar fetch, o xhr, o cualquier otra cosa que estés usando.
Rick Strahl tiene una rutina .js robusta para hacer justamente esto y la recomiendo encarecidamente a todo el mundo. Es una lástima que no sea un npm. (Probablemente no quieras hacer esto en un servidor, sin embargo, ve los comentarios)
