# You Might Not Need an Enums <br /> in Typescript!
@jacklee814
---
## Agenda.
- Features
- Problems
- Alternatives
- Conclusion
- Q&A
- Reference
---
### Features
###### Enums allow a developer to define a set of named constants. <br />(create both a type and a value)
- Numeric base
- String base (v2.4+)
- Heterogeneous enums
- Computed and constant members
- Reverse mappings
- ...more
----
### Numeric base
###### (auto-incremented)
```typescript
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right, // 3
}
enum Direction2 {
Up, // 0
Down, // 1
Left = 66, // 66
Right, // 67
}
```
----
### String base (v2.4+)
###### Allow you to give a meaningful and readable value.
```typescript
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
enum Direction2 {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
// 🚨 ERROR: Enum member must have initializer.
Right,
}
```
----
### Heterogeneous enums
###### (it’s not clear way to do 🤨)
```typescript
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = "YES",
}
```
----
### Computed and constant members
###### binary operators with constant enum expressions as operands <br /> ( +, -, *, /, %, <<, >>, >>>, &, |, ^ )
```typescript
enum ComputedValues {
None = 0,
Friendly = 1 << 0, // 0001 -> 1
Mean = 1 << 1, // 0010 -> 2
Funny = 1 << 2, // 0100 -> 4
Boring = 1 << 3, // 1000 -> 8
All = ~(~0 << 4), // 1111 -> 15
FunnyOrBoring = Funny | Boring, // 12
}
```
----
### Reverse mappings
```typescript
enum Enum {
A,
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
```
---
### Problems
- Runtime cost
- Type safety
- Limitation
----
### Runtime cost
##### Declare without const
```typescript
enum Direction {
Up,
Down,
Left,
Right,
}
```
###### emits code in the JavaScript output. 😨
```typescript
var Direction;
(function (Direction) {
Direction[Direction["Up"] = 0] = "Up";
Direction[Direction["Down"] = 1] = "Down";
Direction[Direction["Left"] = 2] = "Left";
Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
```
----
### Runtime cost
###### Fixed by const declaration.
```typescript
const enum Direction {
Up,
Down,
Left,
Right,
}
```
###### emits code in the JavaScript output. 🙂
```typescript=
//
```
###### But can't using Reverse mappings anymore. 😰
```typescript
const enum Direction {
Up,
}
// 🚨 ERROR: A const enum member can only be accessed using a string literal.
let nameOfUp = Direction[Direction.Up]
```
----
### Type safety
##### When to use Numeric enums.
```typescript
enum Color {
Red,
Blue,
}
// ✅ It's fine 🤔
const Up: Color = 666;
```
----
### Type safety
###### Fixed by String enums.
```typescript
enum Color {
Red = 'Red',
Blue = 'Blue',
}
// 🚨 ERROR: Type '666' is not assignable to type 'Color'.
const primaryColor: Color = 666;
```
----
### Limitation
- Parameters
- Compatibility
----
### Parameters
( Only accept Enum types. )
```typescript
enum Color {
Red = 'Red',
Blue = 'Blue',
}
// 🚨 ERROR: Type '"Red"' is not assignable to type 'Color'.
const primaryColor: Color = 'Red';
// ✅ It's fine, But What if this is a share library 🙃?
const secondaryColor: Color = Color.Blue
```
----
### Compatibility
##### They are't great fit for in JS/TS codebase.
###### [JavaScript enums are in the proposal stage.](https://github.com/Jack-Works/proposal-enum)
---
### Alternatives
- Union type
- Const assertions (v3.4+)
----
### Union type
```typescript
type Color = 'red' | 'blue';
// ✅ Type safety
const rightColor: Color = 'red';
// 🚨 ERROR: Type '"green"' is not assignable to type 'Color'.
const wrongColor: Color = 'green';
```
----
### Const assertions (v3.4+)
###### Its syntax is a type assertion with const in place of the type name.
```typescript
// Type '"hello"'
let x = "hello" as const;
// Object literals get readonly properties
// Type 'readonly [10, 20]'
let y = [10, 20] as const;
// Array literals become readonly tuples
// Type '{ readonly text: "hello" }'
let z = { text: "hello" } as const;
```
----
#### Type with Array and Object
```typescript
const animals = ['cat', 'dog', 'mouse'] as const
// type Animal = "cat" | "dog" | "mouse"
type Animal = typeof animals[number]
const userStatus = {
REGISTERED: 'REGISTERED',
INACTIVE: 'INACTIVE',
NOT_FOUND: 'NOT_FOUND',
} as const;
type TypeUserStatus = typeof userStatus;
// type UserStatus = "REGISTERED" | "INACTIVE" | "NOT_FOUND"
type UserStatus = TypeUserStatus[keyof TypeUserStatus];
```
----
#### Usage
```typescript
const userStatus = {
REGISTERED: 'REGISTERED',
INACTIVE: 'INACTIVE',
} as const;
type TypeUserStatus = typeof userStatus;
type UserStatus = TypeUserStatus[keyof TypeUserStatus];
function showUserStatus(status: UserStatus) {}
showUserStatus(userStatus.REGISTERED);
showUserStatus('REGISTERED');
// 🚨 ERROR: Argument of type '"BANNED"' is not assignable to parameter of type 'UserStatus'.
showUserStatus('BANNED');
```
----
#### What We Got 😏
- Type safety
- More flexible
- Better compatibility
- Reduce code size
---
### Conclusion
> You may not need an enum when an object with as const could suffice.
###### *Typescript official documentation*
---
### Q&A
---
### Reference
- [TypeScript Handbook - Enums](https://www.typescriptlang.org/docs/handbook/enums.html)
- [TypeScript Handbook - const assertions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions)
- [Tidy TypeScript: Prefer union types over enums](https://fettblog.eu/tidy-typescript-avoid-enums/)
- [TypeScript Features to Avoid](https://www.executeprogram.com/blog/typescript-features-to-avoid)
{"metaMigratedAt":"2023-06-17T07:04:03.214Z","metaMigratedFrom":"YAML","title":"You Might Not Need an Enums in Typescript!","breaks":true,"description":"You Might Not Need an Enums in Typescript!","contributors":"[{\"id\":\"fcebd72c-ae71-48a5-9d41-996b5693508b\",\"add\":10261,\"del\":4356}]"}