Skip to content

Commit eda62eb

Browse files
authored
Merge pull request #22 from dphilipson/feature/enum-of-keys
Implement Enum.ofKeys
2 parents 6d13e0a + 5be29b3 commit eda62eb

File tree

3 files changed

+73
-17
lines changed

3 files changed

+73
-17
lines changed

README.md

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ Typesafe string enums in TypeScript.
88

99
* [Installation](#installation)
1010
* [Usage](#usage)
11+
- [Creating and using enums](#creating-and-using-enums)
12+
- [Additional functions](#additional-functions)
13+
- [Enum.isType(enum, value)](#enum-istype-enum-value)
14+
- [Enum.keys(enum)](#enum-keys-enum)
15+
- [Enum.values(enum)](#enum-values-enum)
16+
- [Enum.ofKeys(object)](#enum-ofkeys-object)
1117
* [Motivation](#motivation)
1218
- [Why not built-in enums?](#why-not-built-in-enums)
1319
- [Why not string literals?](#why-not-string-literals)
@@ -25,6 +31,8 @@ This library requires TypeScript 2.2 or later. If you require TypeScript 2.1 com
2531

2632
## Usage
2733

34+
### Creating and using enums
35+
2836
Define an enum as follows:
2937

3038
``` javascript
@@ -89,8 +97,39 @@ export type Status = Enum<typeof Status>;
8997
console.log(Status.RUNNING); // -> "running"
9098
```
9199

92-
Several helper functions are provided. First are `Enum.keys()` and `Enum.values()`, which resemble
93-
`Object.keys()` and `Object.values()` but provide strict typing in their return type:
100+
### Additional functions
101+
102+
#### `Enum.isType(enum, value)`
103+
104+
`Enum.isType` checks if a value is of a given enum type and can be used as a type guard. For example:
105+
106+
``` javascript
107+
const Color = Enum("BLACK", "WHITE");
108+
type Color = Enum<typeof Color>;
109+
110+
let selectedColor: Color;
111+
const colorString = getUserInputString(); // Unsanitized string.
112+
113+
// TypeScript error: Type 'string' is not assignable to type '"BLACK" | "WHITE"'.
114+
selectedColor = colorString;
115+
116+
if (Enum.isType(Color, colorString)) {
117+
// No error this time because within type guard.
118+
selectedColor = colorString;
119+
} else {
120+
throw new Error(`${colorString} is not a valid color`);
121+
}
122+
```
123+
124+
#### `Enum.keys(enum)`
125+
126+
Resembles `Object.keys()`, but provides strict typing in its return type.
127+
128+
#### `Enum.values(enum)`
129+
130+
Resembles `Object.values()`, but provides strict typing in its return type.
131+
132+
Example of both `Enum.keys()` and `Enum.values()`:
94133

95134
``` javascript
96135
const FileType = Enum({
@@ -109,24 +148,22 @@ const values = Enum.values(FileType);
109148
// Return value: ["application/pdf", "text/plain", "image/jpeg"] (not necessarily in that order)
110149
```
111150

112-
Also available is `Enum.isType()`, which checks if a value is of a given enum type and can be used
113-
as a type guard.
151+
#### Enum.ofKeys(object)
152+
153+
Creates a new enum with the same keys as the provided enum or object and whose values are equal to
154+
its keys. This is most useful if for some reason it is necessary to do string comparisons against
155+
the keys of an enum rather than the values. For example:
114156

115157
``` javascript
116-
const Color = Enum("BLACK", "WHITE");
117-
type Color = Enum<typeof Color>;
158+
const ErrorColor = Enum({ OK: "green", ERROR: "red" });
159+
type ErrorColor = Enum<typeof ErrorColor>;
118160

119-
let selectedColor: Color;
120-
const colorString = getUserInputString(); // Unsanitized string.
161+
const ErrorLevel = Enum.ofKeys(ErrorCodes);
121162

122-
// TypeScript error: Type 'string' is not assignable to type '"BLACK" | "WHITE"'.
123-
selectedColor = colorString;
163+
const errorLevel = getErrorLevel();
124164

125-
if (Enum.isType(Color, colorString)) {
126-
// No error because within type guard.
127-
selectedColor = colorString;
128-
} else {
129-
throw new Error(`${colorString} is not a valid color`);
165+
if (errorLevel === ErrorLevel.ERROR) {
166+
...
130167
}
131168
```
132169

__tests__/test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ describe("Enum", () => {
1717
});
1818
});
1919

20+
describe("Enum.ofKeys", () => {
21+
it("returns an object with keys and values equal to keys of input object", () => {
22+
expect(Enum.ofKeys({
23+
BLACK: "black",
24+
WHITE: "white",
25+
})).toEqual({ BLACK: "BLACK", WHITE: "WHITE" });
26+
});
27+
});
28+
2029
describe("Enum.keys", () => {
2130
it("returns the keys of an enum object", () => {
2231
const e = Enum({

src/index.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ export function Enum(...values: any[]): object {
1818
export type Enum<T extends object> = T[keyof T];
1919

2020
export namespace Enum {
21+
export function ofKeys<
22+
T extends { [_: string]: any}
23+
>(e: T): { [K in keyof T]: K } {
24+
const result: any = {};
25+
for (const key of Object.keys(e)) {
26+
result[key] = key;
27+
}
28+
return result;
29+
}
30+
2131
export function keys<
2232
T extends { [_: string]: any }
2333
>(e: T): Array<keyof T> {
@@ -28,8 +38,8 @@ export namespace Enum {
2838
T extends { [_: string]: any }
2939
>(e: T): Array<Enum<T>> {
3040
const result: Array<Enum<T>> = [];
31-
for (const key of keys(e)) {
32-
result.push(e[key as string]);
41+
for (const key of Object.keys(e)) {
42+
result.push(e[key]);
3343
}
3444
return result;
3545
}

0 commit comments

Comments
 (0)