Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting dates properly from an API response in typescript

I have a REST API that gives data in the following format:-

{"id": 1, "name": "New event", "date": "2020-11-14T18:02:00"}

And an interface in my frontend React app like this:-

export interface MyEvent {
  id: number;
  name: string;
  date: Date;
}

I use axios to fetch response from the API.

const response = await axios.get<MyEvent>("/event/1");
const data = response.data;

However, data.date remains a string due to typescript limitations.

This can cause problems later in the code, where I expect all such date fields to be an actual Date object.

I could probably do something like: data.date = new Date(data.date);. But that won't be feasible approach for a lot of reasons.

Is there a better way of handling dates in typescript? How do you handle dates coming from API in response in general?

like image 544
Babri Avatar asked Jan 12 '21 21:01

Babri


People also ask

What is the difference between typescript and JavaScript type casting?

JavaScript doesn’t have a concept of type casting because variables have dynamic types. However, every variable in TypeScript has a type. Type castings allow you to convert a variable from one type to another. In TypeScript, you can use the as keyword or <> operator for type castings.

How to cast an element to another element in typescript?

In TypeScript, you can use the as keyword or <> operator for type castings. The following selects the first input element by using the querySelector () method: Since the returned type of the document.querySelector () method is the Element type, the following code causes a compiler error:

How to use typescript within your web API?

Now, to use TypeScript within our web API, we need to install TypeScript as a developer dependency. # The -D option installs typescript as a developer dependency npm install -D typescript TypeScript contains static type definitions, which enables catching errors during compile time.

How to change the type of a variable in typescript?

However, every variable in TypeScript has a type. Type castings allow you to convert a variable from one type to another. In TypeScript, you can use the as keyword or <> operator for type castings.


2 Answers

So the solution that best fits my use case is similar to the one mentioned by @Amy in the original question's comment.

So I use Axios interceptors to convert dates to a Date object.

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;

For identifying dates, I've used a regex expression, and for conversion to Date object, I've date-fns package.

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);
  }
}
like image 165
Babri Avatar answered Oct 19 '22 14:10

Babri


This subject deserves much more attention than it gets. For me, sanity depends on having all json dates parsed to date objects automagically the moment they show up in my application. The best way to do this is to modify the global JSON object. This is, obviously, a fundamental change to a much-used global api, but it's a change for the better. It works with Axios, without interceptors, and it will also just work if any genius decides to use fetch, or xhr, or whatever else you're having.

Rick Strahl has a robust .js routine for doing just this and I heartily recommend it to the whole world. It's just a pity it's not an npm.

like image 2
bbsimonbb Avatar answered Oct 19 '22 13:10

bbsimonbb