Preferences

Are there any good date/time libraries or utils for TypeScript that prevent you from mixing up variables with different units? E.g. mixing up integer timestamps vs integer durations in seconds vs integer durations in milliseconds.

You're asking for opaque types. This is kinda possible in typescript but you can only approximate it unfortunately.

You may also want to consider a branded type, which can be useful but a little less strict.

I’ve spent way too much time trying to perfect this technique and the best solution (until TS has nominal types, which I think they’re looking at for 4.5) is branding, with a private declared class field that’s optional and always never. Eg

    declare class _MySpecialPrimitive {
      private mySpecialPrimitive?: never;
    }

    type MySpecialPrimitive = number & _ MySpecialPrimitive;
Combined with type guards (which you can conditionally execute at runtime), you can narrow overly broad structural types safely, eg:

    const isMySpecialPrimitive(val: unknown): val is MySpecialPrimitive => /* anything that produces a boolean */
(And you can use assert guards in a similar way, but I find they make it easier to treat them as a noop)
I should add another way I tried to approach this that would be less Type System Theater was Symbols and runtime assignment of brands, eg

    const MySpecialPrimitiveBrand = Symbol('mySpecialPrimitive')

    const val = Object.assign(prevVal, { [MySpecialPrimitiveBrand]: doesntMatter })
Yeah, don’t do that unless you want to destroy every language facility that depends on reference equality checks. It boxes your primitive and breaks the world.
Libs provide something out of the box to do this, e.g. `ts-essentials` provides `Opaque`, so you just write `type DateString = Opaque<string, 'DateString'>`
Their version is essentially my Symbol approach, but only in the type system. This does work, but it has the disadvantage that the type and runtime don't match. It’s certainly better than most Brand types which tend to rely on strings, but I prefer not to expose public properties which don’t exist.

The class/private approach has the advantage of hiding the extra property from everything except the type checker.

I've build a library to do that (based on various known techniques) in [1]; it's also combined with validation based on zod. I would say it's usable but of course having true nominal type support in TypeScript would be way better.

For complex types it also disallows spreading to prevent circumventing validation. However, errors are often not has human readable as one would like them to be.

[1]: https://github.com/renke/vo/tree/master/packages/vod

This item has no comments currently.

Keyboard Shortcuts

Story Lists

j
Next story
k
Previous story
Shift+j
Last story
Shift+k
First story
o Enter
Go to story URL
c
Go to comments
u
Go to author

Navigation

Shift+t
Go to top stories
Shift+n
Go to new stories
Shift+b
Go to best stories
Shift+a
Go to Ask HN
Shift+s
Go to Show HN

Miscellaneous

?
Show this modal