Add description attribute to enum and read this description in TypeScript
Another interesting solution found here is using ES6 Map:
export enum Sample {
V,
IV,
III
}
export const SampleLabel = new Map<number, string>([
[Sample.V, 'FIVE'],
[Sample.IV, 'FOUR'],
[Sample.III, 'THREE']
]);
USE
console.log(SampleLabel.get(Sample.IV)); // FOUR
SampleLabel.forEach((label, value) => {
console.log(label, value);
});
// FIVE 0
// FOUR 1
// THREE 2
A variation of the accepted answer. Replace number
with your enum
type to be more type safe.
export enum Sample {
V,
IV,
III
}
export const SampleLabel = new Map<Sample, string>([
[Sample.V, 'FIVE'],
[Sample.IV, 'FOUR'],
[Sample.III, 'THREE']
]);
TypeScript doesn't allow you to add properties to an enum
element, which at runtime is just a primitive string or number. Instead you have to do something like create a new type which holds references to these elements and also has the methods or properties you want.
Here's one possible way to do it. Start with your plain enum
like this:
enum SampleEnum {
V, IV, III
}
And let's give an interface definition for your extended type. It has a name
, a description
, and a number
. Note that this type is generic so we can narrow down the name
and number
types shortly:
interface ISample<N extends number, S extends string> {
readonly name: S;
readonly description: string;
readonly number: N;
}
Here is a function which can take your SampleEnum
object and return something with the same keys but with values that implement the extended interface:
function makeSample<E extends Record<Extract<keyof E, string>, number>>(
mapping: E
): { [K in Extract<keyof E, string>]: ISample<E[K], K> } {
const ret = {} as { [K in Extract<keyof E, string>]: ISample<E[K], K> };
(Object.keys(mapping).filter(k => k !== (+k) + "") as
(Extract<keyof E, string>)[]
).forEach(k => {
ret[k] = {
name: k,
description: "Blah " + k,
number: mapping[k]
}
});
return ret;
}
That might be a lot of type juggling, but it's basically just extracting the string-valued keys from SampleEnum
(and ignoring the reverse mapping that adds numeric keys to numeric enums at runtime) and building an instance of the extended interface for each one, in a somewhat type-safe way.
Finally, let's create the Sample
value and type which stands in for our enum
:
const Sample = makeSample(SampleEnum);
type Sample = (typeof Sample)[keyof typeof Sample]
Okay, let's use it:
const nameOfIV = Sample.IV.name; // "IV"
console.log(nameOfIV); // "IV"
const numberOfIII = Sample.III.number; // SampleEnum.III
console.log(numberOfIII); // 1
const descriptionOfV = Sample.V.description; // string
console.log(descriptionOfV); // "Blah V"
const goodSample: Sample = Sample.III; // okay
const badSample: Sample = {
name: "II",
description: "oops",
number: 3
}; // error, name doesn't match
Looks reasonable to me. See for yourself. Of course there are other ways to approach it but this should hopefully give you an idea. Hope that helps. Good luck!
Below method will be type safe (auto completion works) and it uses plain object. It is based on this feature of TypeScript.
export enum Sample {
I = 1,
II = 2,
III = 3
}
export const SampleLabel: { [key in Sample]: string } = {
[Sample.I]: "ONE",
[Sample.II]: "TWO",
[Sample.III]: "THREE",
};