@@ -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
1515Given 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+
6184The above pattern also works with string-typed enum members:
6285
6386``` ts
@@ -73,31 +96,26 @@ export const CredentialType = Object.freeze({
7396export 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
103121import { CipherType } from " ./cipher-type" ;
0 commit comments