4 ms·
Depends. Yes, newtyping is pretty awful in TS due to its structural typing (instead of nominal like Rust for example). You could perhaps newtype using a class
by kaoD 5y ago
Depends. Yes, newtyping is pretty awful in TS due to its structural typing (instead of nominal like Rust for example).
You could perhaps newtype using a class (so you can instanceof) or tag via { unit: 'seconds', value: 30 } but that feels awful and seems to be against the ecosystem established practices.
This is indeed one of my gripes with TS typing. I'm spoiled by other languages, but I understand the design choice.
- dbrgn 5y agoYou can do something like this: export interface OpaqueTag<UID> { readonly __TAG__: UID; } export type WeakOpaque<T, UID> = T & OpaqueTag<UID>; And then use it like this to create a newtype: export type PublicKey = WeakOpaque<Uint8Array, {readonly PublicKey: unique symbol}>; To create this newtype, you need to use unsafe casting (`as PublicKey`), but you can use a PublicKey directly in APIs where a Uint8Array is needed (thus "weak opaque").
- spion 5y agoI tried to solve this problem in a way that's reasonably pleasant here https://github.com/spion/branded-types https://github.com/spion/branded-types
- hurflmurfl 5y agoI was recently dealing with some React components at work, where the components would accept as an input the width or the height of the element. Originally, the type signature was type Props = {height: number} This naturally raises the question - number of what? Does "50" mean `50px`, `50vw`, `50em`, `50rem`, `50%`? I've ended up changing the component to only accept pixels and changed the argument to be a string like this: type Props = {height: `${number}px`} Of course, if passing a "0" makes sense, you could also allow that. If you want to also accept, say, `50em`, you could use a union-type for that. I think this could actually work for other units as well. Instead of having `delay(200)`, you could instead have `delay("200ms")`, and have the "ms" validated by type system. Maybe the future will see this getting more popular: type WeightUnit = 'g' | 'grams' | 'kg' | ...; type WeightString = `${number}${WeightUnit}`; function registerPackage(weight: WeightString): void;
- Izkata 5y ago> This naturally raises the question - number of what? Does "50" mean `50px`, `50vw`, `50em`, `50rem`, `50%`? Because it's React, the expectation is "px", using a string with a suffix to override it: https://reactjs.org/docs/dom-elements.html#style https://reactjs.org/docs/dom-elements.html#style
- smichel17 5y agoThe pattern you want here is branding.