From 19baf654ce40ac4fe4a033aed139aea61b30d795 Mon Sep 17 00:00:00 2001 From: Chalarangelo Date: Mon, 24 May 2021 05:00:00 -0400 Subject: [PATCH] Add js enums --- blog_posts/javascript-await-timeout.md | 2 +- blog_posts/javascript-enum.md | 59 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 blog_posts/javascript-enum.md diff --git a/blog_posts/javascript-await-timeout.md b/blog_posts/javascript-await-timeout.md index a6f444ad7..8d79c7c37 100644 --- a/blog_posts/javascript-await-timeout.md +++ b/blog_posts/javascript-await-timeout.md @@ -1,7 +1,7 @@ --- title: How can I add a timeout to a promise in JavaScript? type: question -tags: javascript,promise,timeout +tags: javascript,promise,timeout,class authors: chalarangelo cover: blog_images/walking.jpg excerpt: Oftentimes you might need to add a timeout to a promise in JavaScript. Learn how to do this and more in this short guide. diff --git a/blog_posts/javascript-enum.md b/blog_posts/javascript-enum.md new file mode 100644 index 000000000..523438238 --- /dev/null +++ b/blog_posts/javascript-enum.md @@ -0,0 +1,59 @@ +--- +title: How can I define an enum in JavaScript? +type: question +tags: javascript,object,class,symbol,generator +authors: chalarangelo +cover: blog_images/book-chair.jpg +excerpt: Enums are part of TypeScript, but what about defininf enums in plain old JavaScript? Here are a few way you can do that. +--- + +TypeScript's enums are a very convenient feature present in many other languages. JavaScript, however, does not have a similar concept at this time. But what JavaScript lacks in syntactic sugar it makes up for in terms of flexibility. + +The easiest way to define an enum would be to use `Object.freeze()` in combination with a plain object. This will ensure that the enum object cannot be mutated. + +```js +const daysEnum = Object.freeze({ + monday: 0, + tuesday: 1, + wednesday: 2, + thursday: 3, + friday: 4, + saturday: 5, + sunday: 6 +}); +``` + +Taking this one step further, one could extract the logic into a function with a variable number of arguments and producing a frozen object. There is very little benefit to this technique, so a better alternative would be to create a simple `class`. After all, enums are more common in object-oriented programming languages, so this sounds like a great fit. + +An `Enum` class would only require a `constructor` with a variable number of arguments. Its job is to add each key to the enum object and freeze the newly created instance. A potential enhancement would be to provide access to the enum values as strings. Obviously, this can be accomplished using `Object.keys()`, but a named method could result in a conflict with one of the enum's values, let alone the method polluting the result. + +Using an ES6 symbol is the obvious solution here, as it will not pollute the result of `Object.keys()` and it will never conflict with any values in the enum. Taking this one step further, `Symbol.iterator` would be a great choice as it would allow for the enum to be considered iterable and make it even more useful. Putting all of this together, here's my `Enum` class and how to use it: + +```js +class Enum { + constructor(...keys) { + keys.forEach((key, i) => { + this[key] = i; + }); + Object.freeze(this); + } + + *[Symbol.iterator]() { + for (let key of Object.keys(this)) yield key; + } +} + +const daysEnum = new Enum( + 'monday', + 'tuesday', + 'wednesday', + 'thursday', + 'friday', + 'saturday', + 'sunday' +); + +const days = [...daysEnum]; // Array of the enum values as strings +``` + +**Image credit:** [Taylor Simpson](https://unsplash.com/@taylorgsimpson?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)