Skip to content

Commit ef44b1c

Browse files
committed
refine enum code style guidance
1 parent a24fd75 commit ef44b1c

File tree

1 file changed

+34
-16
lines changed

1 file changed

+34
-16
lines changed

docs/contributing/code-style/enums.md

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use [constant objects][constant-object-pattern] instead of introducing a new enu
1010
- Avoid asserting the type of an enum-like. Use explicit types instead.
1111
- Create utilities to convert and identify enums modelled as primitives.
1212

13-
### Example
13+
### Numeric enum-likes
1414

1515
Given the following enum:
1616

@@ -58,6 +58,29 @@ type CipherContent =
5858
| { type: typeof CipherType.SecureNote, note: EncString, ... }
5959
```
6060
61+
:::warning
62+
63+
Unlike an enum, TypeScript lifts the type of the members of `const CipherType` to `number`. Code
64+
like the following requires you explicitly type your variables:
65+
66+
```ts
67+
// ✅ Do: strongly type enum-likes
68+
let value: CipherType = CipherType.Login;
69+
const array: CipherType[] = [CipherType.Login];
70+
const subject = new Subject<CipherType>();
71+
72+
// ❌ Do not: use type inference
73+
let value = CipherType.Login; // infers `1`
74+
const array = [CipherType.Login]; // infers `number[]`
75+
76+
// ❌ Do not: use type assertions
77+
let value = CipherType.Login as CipherType; // this operation is unsafe
78+
```
79+
80+
:::
81+
82+
### String enum-likes
83+
6184
The above pattern also works with string-typed enum members:
6285

6386
```ts
@@ -73,31 +96,26 @@ export const CredentialType = Object.freeze({
7396
export type CredentialType = CredentialType[keyof typeof CredentialType];
7497
```
7598

76-
:::warning
99+
:::note[Enum-likes are structural types!]
77100

78-
Unlike an enum, TypeScript lifts the type of the members of `const CipherType` to `number`. Code
79-
like the following requires you explicitly type your variables:
101+
Unlike string-typed enums, enum-likes do not reify a type for each member. This means that you can
102+
use their string value or their enum member interchangeably.
80103

81104
```ts
82-
// ✅ Do: strongly type enum-likes
83-
let value: CipherType = CipherType.Login;
84-
const array: CipherType[] = [CipherType.Login];
85-
const subject = new Subject<CipherType>();
105+
let value: CredentialType = CredentialType.Username;
86106

87-
// ❌ Do not: use type inference
88-
let value = CipherType.Login; // infers `1`
89-
const array = [CipherType.Login]; // infers `number[]`
90-
91-
// ❌ Do not: use type assertions
92-
let value = CipherType.Login as CipherType; // this operation is unsafe
107+
// this is typesafe!
108+
value = "email";
93109
```
94110

111+
However, the string-typed values are not always identified as enum members. Thus, when the const
112+
object is in scope, prefer it to the literal value.
113+
95114
:::
96115

97116
## Utilities
98117

99-
The following utilities can be used to maintain type safety after compilation. This code assumes
100-
`const CipherType` is frozen.
118+
The following utilities can be used to maintain type safety at runtime.
101119

102120
```ts
103121
import { CipherType } from "./cipher-type";

0 commit comments

Comments
 (0)