Updated “Branding” for a Strongly-Typed Date String in TypeScript

In 2017 I wrote a blog post about using nominal typing in TypeScript to support statically typing ISO8601 strings: DateStr – A Strongly-Typed Date String for TypeScript.

Changes to TypeScript since then have made the particular technique I was using for “branding” a string less than ideal. Here, I’ll update the branding strategy so that the DateStr type works properly in newer versions of TypeScript.

The Problem

As this StackOverflow question illustrates, in recent versions of TypeScript (anything greater than or equal to 3.6.3 it appears), the actual type of a DateStr is never. You can see this by hovering over a variable that’s typed as DateStr. Or if you, as the StackOverflow poster did, try to call a string function on a DateStr, it won’t compile.

Some experimenting with a TypeScript playground shows that as of TypeScript 3.5.1, that was not the case. If you open that playground and hover over the today variable at the bottom, you’ll see it’s a DateStr (as originally intended).

However, say you change the version of TypeScript to something more recent (4.6.2 is the latest in the playground at the time of writing). If you hover over today, it will show never. That’s not desirable.

Better Branding

Rather than the enum technique I used back in 2017, the following technique seems better now (as one of the answers to the question indicated).


  export type DateStr = string & { __brand: 'DateStr' }

In an updated playground, you can see that in a recent version (4.6.2) of TypeScript, if you hover over today you get the expected DateStr type. It also still works if you switch to the older 3.5.1 version as well.

Conclusion

I still think there’s a ton of value in having a statically typed string representation of a Date (or a DateTime). And fortunately, updating the definition of the DateStr so it’s more compatible with recent versions of TypeScript is easy and won’t affect anything else in a codebase.