Using Typescript to recursively convert dates to strings

March 17, 2022

Jeremy Sarchet
Full Stack Developer

If you work with TypeScript you may be familiar with “utility types”, which take a given type and transform it somehow into a different type. It’s a function which takes a type as an input and modifies it and returns a new type. TypeScript has many built-in utility types, which are detailed here: TypeScript’s introductory article on utility types

The built-in utility types are great, but you can also make your own. Here’s one we’ve made which is extra special:

type RecursivelyConvertDatesToStrings = T extends Date
	? string
	: T extends Array<infer U>
	? RecursivelyConvertDatesToStrings<U>[]
	: T extends object
	? { [K in keyof T]: RecursivelyConvertDatesToStrings<T[K]> }
	: T;

This is a utility type which takes anything you throw at it, objects, arrays, primitives, you name it, and converts Date values to string. It’ll then be strings-for-dates all the way down

Fun fact

One of our engineers, Robert Cooper, implemented this utility type, with the help of GitHub’s AI code-writing-assistant, Copilot.

Our use case: server-side vs. client-side typing

We use RecursivelyConvertDatesToStrings to transform the typings of our endpoint responses (typically ORM models arranged and prepped in one form or another) from how they look server-side, into how they arrive client-side, upon a fetch operation. Because our endpoints return data via JSON in the standard way, there’s no way for any Date fields to arrive in-tact. They’re necessarily flattened into strings for the HTTP response.

So, we type our “fetched endpoint responses”, by taking our server-side “endpoint responses” and running them through this utility type. That way TypeScript knows that all our favorite date fields, such as createdAt or updatedAt are now of string type, and our client-side state and rendering code set up for success.

You may not have this use case though

Some applications might benefit from a client-side layer which automatically intercepts fetched payloads and reconstitutes proper JavaScript Date objects from strings that match a date. We considered this, but decided that for our needs, it’s sufficient to do any Date reconstitution manually, as needed, for a given operation client-side.


More posts like this

Make your database collaborative in as little as 90 seconds

See how removing barriers can change the way your team works.

No credit card required