Proposal for slight improvement to the definition of Newtype
Because Newtype is defined like this
export interface Newtype<URI, A> {
readonly _URI: URI
readonly _A: A
}
and the convention generally used for defining a URI is to use in interface with a unique symbol field, like this
export interface NonNegative extends Newtype<{ readonly NonNegative: unique symbol }, number> {}
TypeScript permits us to access the _URI and _A fields, even though the values don't actually exist. Everyone's just supposed to know not to do that. If instead we required the URI parameter to be a unique symbol type, we can actually make the fields for the phantom type parameters no longer accessible (as long as the unique symbol value isn't exported from the module it's defined in). We can do so like this:
declare const unique_symbol: unique symbol
type UniqueSymbol<Sym extends symbol> = symbol extends Sym ? typeof unique_symbol : symbol
export type Newtype<URI extends UniqueSymbol<URI>, A> = {
readonly [K in URI]: A
}
With this version of Newtype, you would define NonNegative like so:
declare const NonNegativeURI: unique symbol
interface NonNegative extends Newtype<typeof NonNegativeURI, number> {}
With this type, as long as NonNegativeURI is not exported, nobody can access or even see the internal phantom field. And you can see in the TS Playground below that only unique symbols are allowed to be passed as the URI.
I just wanted to share this idea in case others might consider it an improvement to the definition of Newtype and perhaps it could be implemented in newtype-ts in the future.