Article summary
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.