2022-07-06 09:08:37 +01:00
|
|
|
---
|
2022-09-06 15:44:40 +01:00
|
|
|
categories:
|
|
|
|
- Programming Languages
|
2022-07-06 09:08:37 +01:00
|
|
|
tags:
|
|
|
|
- typescript
|
|
|
|
---
|
|
|
|
|
|
|
|
# Enums
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
In essence an `enum` in TypeScript is an incremented store of immutable
|
|
|
|
variables. The only way I can understand them is just to think of them as a bag
|
|
|
|
of constants.
|
2022-07-06 09:08:37 +01:00
|
|
|
|
|
|
|
Below is an example of an `enum`:
|
|
|
|
|
|
|
|
```ts
|
|
|
|
enum Continents {
|
|
|
|
NorthAmerica,
|
|
|
|
SouthAmerica,
|
|
|
|
Africa,
|
|
|
|
Asia,
|
|
|
|
Europe,
|
|
|
|
Antartica,
|
|
|
|
Australia,
|
|
|
|
}
|
|
|
|
|
|
|
|
// usage
|
|
|
|
var region = Continents.Africa;
|
|
|
|
```
|
|
|
|
|
|
|
|
Here is an example of a string-based enum from the Studio codebase:
|
|
|
|
|
|
|
|
```tsx
|
|
|
|
export enum HelpLinksEnum {
|
2024-02-02 15:58:13 +00:00
|
|
|
composerView = "composerView",
|
|
|
|
conditionalHelp = "conditionalHelp",
|
|
|
|
configView = "configView",
|
|
|
|
dashboard = "dashboard",
|
|
|
|
dataView = "dataView",
|
|
|
|
functionHelp = "functionHelp",
|
|
|
|
previewMode = "previewMode",
|
2022-07-06 09:08:37 +01:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Main properties
|
|
|
|
|
|
|
|
- **Auto-incrementation (numeric enums only):**
|
|
|
|
- Enums are auto-incrementing.
|
2024-02-02 15:58:13 +00:00
|
|
|
- If we wanted to change the automatic sequence we could do something like the
|
|
|
|
below and TS would automatically update the index to reflect our change
|
2022-07-06 09:08:37 +01:00
|
|
|
```ts
|
|
|
|
enum NewProjectMenuItems {
|
|
|
|
Row = 5
|
|
|
|
Table // would automatically become `6` in the index
|
|
|
|
}
|
|
|
|
```
|
|
|
|
- **Enums are types**
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
- Enums are interpreted as types by TS. Consequently we can an enum as a type
|
|
|
|
annotation. This can be particularly useful when typing function parameters.
|
|
|
|
For example:
|
2022-07-06 09:08:37 +01:00
|
|
|
|
|
|
|
```ts
|
|
|
|
enum UserResponse {
|
|
|
|
No = 0,
|
|
|
|
Yes = 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
function respond(recipient: string, message: UserResponse): void {
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
- **Enums accept computed values**
|
2024-02-02 15:58:13 +00:00
|
|
|
- As is the case with objects generally, we are not limited to primitive data
|
|
|
|
types when setting values on enums, we can also assign functions.
|
2022-07-06 09:08:37 +01:00
|
|
|
- **Reverse mapping**
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
- Reverse mapping is the ability to access a key via its value in addition to
|
|
|
|
the more standard practice of accessing a value via its key.
|
2022-07-06 09:08:37 +01:00
|
|
|
- Demonstration:
|
|
|
|
|
|
|
|
```ts
|
|
|
|
enum PrintMedia {
|
|
|
|
Newspaper = 1,
|
|
|
|
Newsletter,
|
|
|
|
Magazine,
|
|
|
|
Book,
|
|
|
|
}
|
|
|
|
|
|
|
|
PrintMedia.Magazine; // returns 3
|
2024-02-02 15:58:13 +00:00
|
|
|
PrintMedia["Magazine"]; // returns 3
|
2022-07-06 09:08:37 +01:00
|
|
|
PrintMedia[3]; // returns Magazine
|
|
|
|
```
|
|
|
|
|
|
|
|
- **Useful in switch statements**
|
2024-02-02 15:58:13 +00:00
|
|
|
- Enums come in handy when you want to reduce the verbosity and repetition of
|
|
|
|
a large switch statement.
|
2022-07-06 09:08:37 +01:00
|
|
|
- The following is an example from the codebase:
|
|
|
|
```tsx
|
|
|
|
public projectMenuItemClickHandler(e: IUserProjectMenuItemClick): void {
|
|
|
|
switch (e.menuItem) {
|
|
|
|
case UserProjectMenuItems.Rename:
|
|
|
|
e.item.rename = true;
|
|
|
|
break;
|
|
|
|
case UserProjectMenuItems.Export:
|
|
|
|
this.exportProject(e.item);
|
|
|
|
break;
|
|
|
|
case UserProjectMenuItems.Clone:
|
|
|
|
this.cloneProject(e.item);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Main benefits
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
More generally, by using enums we ensure that a given data structure is
|
|
|
|
preserved unaltered and intact throughout the codebase which is very useful when
|
|
|
|
multiple developers are working with the same classes and components. This
|
|
|
|
creates a high-level canonical form of a given data structure that may be used
|
|
|
|
in multiple contexts. This reduces the likelihood of different developers
|
|
|
|
'reinventing the wheel' and duplicating common data structures, helping to
|
|
|
|
promote modularity and minimise technical debt.
|
2022-07-06 09:08:37 +01:00
|
|
|
|
|
|
|
### Constraints and best practices
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
There are some important constraints that should be borne in mind when using
|
|
|
|
enums:
|
2022-07-06 09:08:37 +01:00
|
|
|
|
|
|
|
- **Initialise string enums!**
|
2024-02-02 15:58:13 +00:00
|
|
|
- String enums must be initialised with a string or a reference to another
|
|
|
|
enum. They cannot be tacitly defined as is the case with numeric enums
|
2022-07-06 09:08:37 +01:00
|
|
|
- **Don't mix data types!**
|
2024-02-02 15:58:13 +00:00
|
|
|
- It is technically possible to construct an enum that contains both numbers
|
|
|
|
and strings but this should be avoided as it can lead to unintended
|
|
|
|
side-effects in the incrementation process. It also kind of undermines the
|
|
|
|
purpose of enums. In this scenario, a custom type would probably be more
|
|
|
|
appropriate.
|
2022-07-06 09:08:37 +01:00
|
|
|
- **Strings only as keys**
|
2024-02-02 15:58:13 +00:00
|
|
|
- In contrast to a `Map` or object an enum cannot have a numeric key. It must
|
|
|
|
always be a string.
|