> You can always cast your way around nominal typing, even with enums. So you can do:
> doSomethingBar('No' as Bar);
I think you can avoid that by not export type `Bar`. I think Bar then acts as an abstract type.
On the other hand with, the branded version, even if you do not avoid exporting the type, even with when branded the object type, you can still get one enum masquerading as another by using the same name. See below where the original Foo is in enums.ts:
import { Foo as Foo2, doSomething } from './enums'
// And now, this will work:
doSomething(Foo2.two);
// But this will error:
doSomething('2');
// this is also an error since the type is not exported
doSomething('2' as Foo2);
type Enum<T> = {
[K in keyof T]: T[K] & {__brand: T};
}
const _Foo = {
one: '1',
two: '2',
three: '3'
} as const;
export const Foo = _Foo as Enum<typeof _Foo>;
type ValueOf<X> = X[keyof X];
type Foo = ValueOf<typeof Foo>;
// no type error
doSomething(Foo.two);
I thought enums was the only way to get truly unique types in typescript, but I would be happy to be wrong here.