Re:You may not need Moment.js
by eyelidlessness on Saturday September 18, 2021 @08:32PM
(#28580625)
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
Combined with type guards (which you can conditionally execute at runtime), you can narrow overly broad structural types safely, eg:
(And you can use assert guards in a similar way, but I find they make it easier to treat them as a noop)
[ Parent
| on HN ]
Re:You may not need Moment.js
by eyelidlessness on Saturday September 18, 2021 @10:43PM
(#28581264)
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.
Re:You may not need Moment.js
by jestar_jokin on Sunday September 19, 2021 @10:37PM
(#28589897)
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'>`
Re:You may not need Moment.js
by eyelidlessness on Monday September 20, 2021 @04:02PM
(#28598231)
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.