@@ -82,7 +82,7 @@ console.log(state);
8282// I hope you're not expecting other services to send you objects that look like this.
8383```
8484
85- ### Why not string literals
85+ ### Why not string literals?
8686
8787Using string literals throughout a program leaves it vulnerable to bugs caused by typos or
8888incomplete refactors. For example:
@@ -139,7 +139,10 @@ provide the best of both worlds: string enums with the convenience of built-in e
139139
140140## How It Works
141141
142- This section is not necessary to use this library, but for those curious about how it is implemented, read on.
142+ This section is not necessary to use this library, but for those curious about how it is
143+ implemented, read on. The explanation uses the concepts of index types and mapped types, as
144+ described in TypeScript's
145+ [ Advanced Types] ( https://www.typescriptlang.org/docs/handbook/advanced-types.html ) page.
143146
144147The entire source of this library is
145148
@@ -153,19 +156,27 @@ export function Enum<V extends string>(...values: V[]): { [K in V]: K } {
153156export type Enum < T > = T [keyof T ];
154157```
155158
156- We are creating a function named ` Enum ` and a type named ` Enum ` , so both can be imported with a single symbol.
159+ We are creating a function named ` Enum ` and a type named ` Enum ` , so both can be imported with a
160+ single symbol.
157161
158- The type signature
162+ In TypeScript, a string constant is a type (for example, in ` const foo = "Hello" ` , the
163+ variable ` foo ` is assigned type ` "Hello" ` ). This means that the array
159164
160165``` javascript
161- function Enum<V extends string>( ... values : V []): { [ K in V ] : K } {
166+ [ " RUNNING " , " STOPPED " ]
162167```
163168
164- can be read as follows: take in an array of strings and call the different types ` V ` . A string
165- constant is a type in TypeScript (for example, ` const foo = " hello" ` assigns the type ` " hello" `
166- to ` foo` ), so ` V ` is actually multiple string literal types. Then ` { [K in V ]: K }` describes an
167- object whose keys are the types that make up ` V ` and for each such key has a value equal to that
168- key. Hence, the type of ` Enum (" RUNNING" , " STOPPED" )` is
169+ can be inferred to have type ` ("RUNNING" | "STOPPED")[] ` , and so when it is passed into a function
170+ with type signature
171+
172+ ``` javascript
173+ function Enum<V extends string>(... values : V []): { [K in V ]: K }
174+ ```
175+
176+ the type parameter ` V ` is thus inferred to be ` "RUNNING" | "STOPPED" ` . Then the return type
177+ ` { [K in V]: K } ` is a mapped type which describes an object whose keys are the types that
178+ make up ` V ` and for each such key has a value equal to that key. Hence, the type of
179+ ` Enum("RUNNING", "STOPPED") ` is
169180
170181``` javascript
171182// This is a type, not an object literal.
@@ -181,11 +192,12 @@ Next, consider the definition
181192type Enum< T > = T [keyof T ];
182193```
183194
184- This describes, for a given keyed type ` T ` , the type obtained by taking the values of ` T ` when
185- passing in each key (the syntax ` T [keyof T ]` is meant to evoke ` t[key]` for each ` key` in ` t` ). When
186- applied to the type from the previous step, we end up with the union of the types of the values,
187- hence ` Enum< typeof Enum (" RUNNING" , " STOPPED" )> ` evaluates to ` " RUNNING" | " STOPPED" ` , which is what
188- we want.
195+ This is an index type which describes, for a given keyed type ` T ` , the type obtained by indexing
196+ into ` T ` with an arbitrary one of its keys (the syntax ` T[keyof T] ` is meant to evoke the
197+ expression ` t[key] ` for some ` key ` in ` t ` ). When passing in an arbitrary key to the object from the
198+ previous step, we get a value which might be any one of the object's values, and so its type is thus
199+ the union of the types of the object's values. Hence, ` Enum<typeof Enum("RUNNING", "STOPPED")> `
200+ evaluates to ` "RUNNING" | "STOPPED" ` , which is what we want.
189201
190202## Acknowledgements
191203
0 commit comments