4 ms·
Check out what are often called tagged types. You basically define a `type A = string &{a: SomeSymbol}` And then have a type assertion function that just retu
by mcfedr 2y ago
Check out what are often called tagged types.
You basically define a `type A = string &{a: SomeSymbol}`
And then have a type assertion function that just returns true, and you have control over the places A can come from
- Waterluvian 2y agoAh yeah I remember poking at that. I should review it again. I think at the time it felt like a bit of a hack, but maybe some features of the past years of TS updates have helped. I assume the idea is to lie to the type system about the existence of the symbol, and at runtime it is just a string.
- TOGoS 2y agoTo me it feels like less of a hack if I can make the type declaration not a lie. e.g. type FooID = string & { typeName? : "FooID" } Read as 'of course this thing doesn't have a typeName[1] property, since it's a string, but if it did have the property, the value would be "FooID"'. You can then cast between FooID and string, but not between FooID and some other type that declares a typeName property. [1] I actually tend to use 'classRef' with an RDFish long name for the type, but that makes examples longer and isn't the point.
- Waterluvian 2y agoThat’s a really helpful way of framing it. I’m tempted to try this with our uuid type and see how well it works. I think I’ll also try to base it on a template string too if that’s possible. Given we use a standard dash segmented uuid string.
- demurgos 2y agoYes, it's the standard way if you want implicit compat with the base type, so you can pass a value of type `A` to a function expecting a `string`. An other name for this pattern is "branded types".
- steve_adams_86 2y agoI really like the Effect schema library for tagged types. I’m not sure how well it works for primitives, though.