Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Brand all Enums #2952

Open
LukeAbby opened this issue Dec 8, 2024 · 0 comments
Open

Brand all Enums #2952

LukeAbby opened this issue Dec 8, 2024 · 0 comments
Labels
good first issue Good for newcomers

Comments

@LukeAbby
Copy link
Collaborator

LukeAbby commented Dec 8, 2024

I've added a new Brand type to helperTypes. One of the things it's most useful for are enums.

The pattern to implement is as follows:

namespace ExampleClass {
    type EXAMPLE_ENUM = Brand<number, "ExampleClass.EXAMPLE_ENUM">;
}

declare class ExampleClass {
    static EXAMPLE_ENUM: Record<"a" | "b" | "c", ExampleClass.EXAMPLE_ENUM>;

    usesEnum(value: ExampleClass.EXAMPLE_ENUM);
}

const exampleClass = new ExampleClass();
exampleClass.usesEnum(ExampleClass.EXAMPLE_ENUM.a); // Works
exampleClass.usesEnum(1); // Fails

This helps people use enums appropriately and avoid mistakes.


Brand is implemented as follows:

declare class Branded<in out BrandName extends string> {
  #brand: BrandName;
}

export type Brand<BaseType, BrandName extends string> = BaseType & Branded<BrandName>;

The principle is that the truly private property #brand must exist for it to be assignable. This property does not really exist at runtime but its existence is expected at compile time and so has these useful properties.

This can't be replicated outside of going through the Brand type because the Branded class does not exist anywhere else and a truly private property from one class is not assignable to another. A similar effect could be achieved through a unique symbol but this would show up in keyof Brand<...> hence why a truly private property is used. Plus it would make it more difficult to make BrandName explicitly invariant outside of a class.

@LukeAbby LukeAbby added the good first issue Good for newcomers label Dec 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

1 participant