Skip to content

Instantly share code, notes, and snippets.

@aparx
Last active February 14, 2023 20:10
Show Gist options
  • Save aparx/b14d6b1464b6492fdc5526a882473e02 to your computer and use it in GitHub Desktop.
Save aparx/b14d6b1464b6492fdc5526a882473e02 to your computer and use it in GitHub Desktop.
typescript enums without using enum
type EnumKey<EnumType> = keyof EnumType;
type IdentityEnum<T> = T extends Array<infer E extends string> ? {
readonly [P in T[keyof T] as E]: E
} : never;
type IdentityEnumConstructor = {
<T extends string[]>(...values: T): IdentityEnum<T>;
new <T extends string[]>(...values: T): IdentityEnum<T>;
};
type EnumField<T> = T extends IdentityEnum<string[]>
? keyof T : T extends string
? T : never;
const IdentityEnum = function<T extends string[]>(...names: T) {
const obj: Partial<IdentityEnum<T>> = {};
for (const name of names) {
(obj as any)[name] = name;
}
return {...obj} as const;
} as IdentityEnumConstructor;
@aparx
Copy link
Author

aparx commented Feb 14, 2023

Example

// We construct a new enum and a type to be able to reference an enum field
const Language = IdentityEnum('English', 'German', 'Italian');
type Language = EnumField<typeof Language>;

// Some random object that has our enum keys as property keys
const abbreviations: Record<Language, string> = {
    [Language['English']]: 'EN',
    [Language['German']]: 'GER',
    [Language['Italian']]: 'ITA',
    // or
    'English': 'EN',
    'German': 'GER',
    'Italian': 'ITA',
};

console.log(Language['German']);    
// [LOG]: German

console.log(abbreviations[Language['German']]);
// [LOG]: GER
console.log(abbreviations['German']);
// [LOG]: GER

Example on typescript playground

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment