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

XS✔ ◾ Typescript Enums Rule #8193

Merged
merged 31 commits into from Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
51f90f5
added base rule
Harry-Ross Mar 5, 2024
6886550
added bits to include object const assertions
Harry-Ross Mar 19, 2024
4fe5aa9
Added image of vscode use
Harry-Ross Mar 19, 2024
9aabc57
added vscode screenshots for object const assertions
Harry-Ross Mar 19, 2024
4ad8a2b
bit of content cleanup
Harry-Ross Mar 19, 2024
52593ed
added intro sentence
Harry-Ross Mar 19, 2024
3a9e3aa
added correct timestamp
Harry-Ross Mar 19, 2024
6fa0855
Merge branch 'main' into typescript-enums-rule
Harry-Ross Mar 19, 2024
7cc13d9
Auto-fix Markdown files
github-actions[bot] Mar 20, 2024
2240d01
Update rules/typescript-enums/rule.md
tiagov8 Mar 21, 2024
b18e96f
Auto-fix Markdown files
github-actions[bot] Mar 21, 2024
cc875ed
Update rules/typescript-enums/rule.md
Harry-Ross Mar 21, 2024
575390b
Update rules/typescript-enums/rule.md
Harry-Ross Mar 21, 2024
74a6e7a
Update rules/typescript-enums/rule.md
Harry-Ross Mar 21, 2024
22603e8
Update rules/typescript-enums/rule.md
Harry-Ross Mar 21, 2024
00d0975
Auto-fix Markdown files
github-actions[bot] Mar 21, 2024
d6e8f59
Update rules/typescript-enums/rule.md
Harry-Ross Mar 22, 2024
4daa013
Auto-fix Markdown files
github-actions[bot] Mar 22, 2024
7c10bef
made jeoffrey's requested changes
Harry-Ross Mar 22, 2024
ddce942
requested changes from jeoffrey
Harry-Ross Mar 22, 2024
6a08e9b
Auto-fix Markdown files
github-actions[bot] Mar 22, 2024
dfecef8
changed title to be more readable
Harry-Ross Mar 22, 2024
21d8931
Update rules/typescript-enums/rule.md
Harry-Ross Mar 26, 2024
88f57f6
Update rules/typescript-enums/rule.md
Harry-Ross Mar 26, 2024
2aeed33
added point about consts
Harry-Ross Mar 26, 2024
dadd42b
Merge branch 'typescript-enums-rule' of https://github.com/SSWConsult…
Harry-Ross Mar 26, 2024
fae38c7
added headings + good and bad examples
Harry-Ross Mar 26, 2024
e827877
Auto-fix Markdown files
github-actions[bot] Mar 26, 2024
7f70f66
Added sentence at bottom for usage of when an enum is preferred
Harry-Ross Mar 26, 2024
7400713
Merge branch 'typescript-enums-rule' of https://github.com/SSWConsult…
Harry-Ross Mar 26, 2024
015dc10
added single source of truth part to sentence
Harry-Ross Mar 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -6,6 +6,7 @@ uri: rules-to-better-typescript
index:
- avoid-using-any
- describe-types-sparsely
- typescript-enums
- follow-good-object-oriented-design-patterns
- good-typescript-configuration
- only-export-what-is-necessary
Expand Down
Binary file added rules/typescript-enums/icon-vscode-sense.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added rules/typescript-enums/iconkey-vscode-sense.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 127 additions & 0 deletions rules/typescript-enums/rule.md
Harry-Ross marked this conversation as resolved.
Show resolved Hide resolved
@@ -0,0 +1,127 @@
---
type: rule
title: Do you know why to use const assertions instead of TypeScript enums?
uri: typescript-enums
authors:
- title: Harry Ross
url: https://ssw.com.au/people/harry-ross
related:
- use-enums-instead-of-hard-coded-strings
created: 2024-03-19T21:39:38.906Z
archivedreason: null
guid: ba19be99-354d-44b2-a2da-4131cc660f18
---
It's super important to ensure that [magic strings are not used in your codebase](https://www.ssw.com.au/rules/use-enums-instead-of-hard-coded-strings/). Typically, we would use constant values or enums to solve this problem, but this may not be applicable when using TypeScript. You might expect TypeScript enums to function like strongly typed languages like C# but often this is not the case.

<!--endintro-->

`youtube: jjMbPt_H3RQ`
**Video: Enums considered harmful (9 min)**

While TypeScript enums provide a lot of useful type safety at runtime, it's very important to consider that there may be cleaner options.

## Numerical Enums

When you define an enum like this:

```ts
enum Fruits {
Apple,
Banana,
Cherry
}
```

When compiled to JavaScript, it looks like:

```js
var Fruits;
(function (Fruits) {
Fruits[Fruits["Apple"] = 0] = "Apple";
Fruits[Fruits["Banana"] = 1] = "Banana";
Fruits[Fruits["Cherry"] = 2] = "Cherry";
})(Fruits || (Fruits = {}));
```

However, this makes it hard to loop over the keys of the enum, as when you run `Object.keys(Fruits)` you would get the following array returned:
Harry-Ross marked this conversation as resolved.
Show resolved Hide resolved

::: bad

```ts
["0", "1", "2", "Apple", "Banana", "Cherry"]
```

**Bad Example - an irritating DX, instead of returning just the values of the enum**
:::

Instead, a much cleaner option is by using [const assertions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions). With const assertions we can be sure the code is using the string values we want:

```ts
const fruits = ["Apple", "Banana", "Cherry"] as const;
```

Now, if we look into the content of the shapes array using:

```ts
type Fruit = typeof fruits[number];
```

We can construct this type from the above array, which is equivalent to:

::: good

```ts
type Fruit = "Apple" | "Banana" | "Cherry";
```

**Good Example - a much cleaner DX**
:::

This makes it super easy to loop over keys within a union type. This also allows us to be able to pass `"Apple"` into a function that takes `Fruit` as an argument. We get super useful feedback from our code editor - the same as a typical TypeScript union type from VSCode from the `Fruit` union type:

![Figure: Working VSCode Intellisense that works with all const assertions](vscode-intellisense-array2.png)

Harry-Ross marked this conversation as resolved.
Show resolved Hide resolved
## String Enums

::: bad

```tsx
enum Icon {
sun = "sun",
moon = "moon"
}

const icons: Record<Icon, string> = {
Harry-Ross marked this conversation as resolved.
Show resolved Hide resolved
sun: "sun_12345.jpg",
moon: "moon_543212.jpg"
};
```

**Bad Example - duplication of key values where it is not needed**
:::

Harry-Ross marked this conversation as resolved.
Show resolved Hide resolved
This is problematic, as it provides us no useful type hints for object values, as object values are typed as `string`, and there is an unecessary duplication of object keys. For cases like this with a single source of truth (i.e. the `icons` object), we can use const assertions, similiar to above with objects:

::: good

```tsx
const icons = {
sun: "sun_12345.jpg",
moon: "moon_543212.jpg",
} as const;
Harry-Ross marked this conversation as resolved.
Show resolved Hide resolved

type IconKey = keyof typeof icons; // "sun" | "moon" union type

type Icon = (typeof icons)[IconKey]; // "sun_12345.jpg" | "moon_543212.jpg" union type
Harry-Ross marked this conversation as resolved.
Show resolved Hide resolved
```

**Good Example - a much cleaner DX with a single source of truth in the `as const` object**
:::

Similar to the array const assertion above, these also provide useful type hints in your code editor:

![Figure: Using the Icon type from above](icon-vscode-sense.png)

![Figure: The IconKey type from above](iconkey-vscode-sense.png)

Remember, it's important to assess on a case-by-case basis when you are writing code to determine whether a const assertion can be used instead of an enum. For example, it's important when dealing with object values you don't want to overlap (i.e. `Icon1`, `Icon2` both with a `moon` key but with different moon images) to opt for enums. However, using const assertions will likely lead to better DX (Developer eXperience) in most cases.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.