Skip to content

Commit 408b67d

Browse files
committed
feat: remove case transformation , startIndex and improve JsDoc examples
1 parent 02f1a93 commit 408b67d

File tree

2 files changed

+41
-74
lines changed

2 files changed

+41
-74
lines changed

source/union-to-enum.d.ts

Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,8 @@
1-
import type {ApplyDefaultOptions} from './internal/object.d.ts';
21
import type {UnionToTuple} from './union-to-tuple.d.ts';
32
import type {UnknownArray} from './unknown-array.d.ts';
4-
import type {BuildTuple} from './internal/tuple.d.ts';
5-
import type {CamelCase} from './camel-case.d.ts';
63
import type {Simplify} from './simplify.d.ts';
74
import type {IsNever} from './is-never.d.ts';
85

9-
/**
10-
{@link UnionToEnum} Options.
11-
*/
12-
type UnionToEnumOptions = {
13-
/**
14-
The starting **Index** of Numeric enums.
15-
16-
@default 1
17-
*/
18-
startIndex?: number;
19-
/**
20-
Whether to use **CamelCase** for property names.
21-
22-
@default false
23-
*/
24-
camelCase?: boolean;
25-
};
26-
27-
type DefaultUnionToEnumOptions = {
28-
startIndex: 1;
29-
camelCase: false;
30-
};
31-
326
/**
337
Converts a union or tuple of property keys (string, number, or symbol) into an **Enum**-like object.
348
@@ -37,37 +11,39 @@ The keys are preserved, and their values are either:
3711
- Their own literal values (by default)
3812
- Or numeric indices (`1`, `2`, ...) if `Numeric` is `true`
3913
40-
By default, **Property** names are not **CamelCased** and **Numeric Enums** start from **Index `1`**. See {@link UnionToEnumOptions} to change this behaviour.
41-
42-
This is useful for creating strongly typed enums from a union of literals.
14+
This is useful for creating strongly typed enums from a union/tuple of literals.
4315
4416
@example-types
4517
```
18+
import type {UnionToEnum} from 'type-fest';
19+
4620
type E1 = UnionToEnum<'A' | 'B' | 'C'>;
4721
//=> { A: 'A'; B: 'B'; C: 'C' }
4822
4923
type E2 = UnionToEnum<'X' | 'Y' | 'Z', true>;
5024
//=> { X: 1; Y: 2; Z: 3 }
5125
52-
type E3 = UnionToEnum<['Play', 'Pause', 'Stop'], true, {startIndex: 3}>;
53-
//=> { Play: 3; Pause: 4; Stop: 5 }
26+
type E3 = UnionToEnum<['Play', 'Pause', 'Stop'], true>;
27+
//=> { Play: 1; Pause: 2; Stop: 3 }
5428
55-
type E4 = UnionToEnum<['some_key', 'another_key'], false, {camelCase: true}>;
56-
//=> { someKey: 'some_key'; anotherKey: 'another_key' }
29+
type E4 = UnionToEnum<['some_key', 'another_key']>;
30+
//=> { 'some_key': 'some_key'; 'another_key': 'another_key' }
5731
5832
type E5 = UnionToEnum<never>;
5933
//=> {}
6034
```
6135
6236
@example-function
6337
```
38+
import type {UnionToEnum, CamelCasedProperties} from 'type-fest';
39+
6440
const verb = ['write', 'read', 'delete'] as const;
6541
const resrc = ['file', 'folder', 'link'] as const;
6642
6743
declare function createEnum<
6844
const T extends readonly string[],
6945
const U extends readonly string[],
70-
>(x: T, y: U): UnionToEnum<`${T[number]}_${U[number]}`, false, {camelCase: true}>;
46+
>(x: T, y: U): CamelCasedProperties<UnionToEnum<`${T[number]}_${U[number]}`>>;
7147
7248
const Template = createEnum(verb, resrc);
7349
//=> {
@@ -90,25 +66,21 @@ const Template = createEnum(verb, resrc);
9066
export type UnionToEnum<
9167
Keys extends PropertyKey | readonly PropertyKey[],
9268
Numeric extends boolean = false,
93-
Options extends UnionToEnumOptions = {},
94-
> = ApplyDefaultOptions<UnionToEnumOptions, DefaultUnionToEnumOptions, Options> extends infer ResolvedOptions extends Required<UnionToEnumOptions>
95-
? IsNever<Keys> extends true ? {}
96-
: _UnionToEnum<[
97-
...BuildTuple<ResolvedOptions['startIndex']>,
98-
...[Keys] extends [UnknownArray] ? Keys : UnionToTuple<Keys>,
99-
], Numeric, ResolvedOptions['camelCase']>
100-
: never;
69+
> = IsNever<Keys> extends true ? {}
70+
: _UnionToEnum<[never, // Shift the index by 1
71+
...[Keys] extends [UnknownArray] ? Keys : UnionToTuple<Keys>,
72+
], Numeric>;
10173

74+
/**
75+
Core type for {@link UnionToEnum}.
76+
*/
10277
type _UnionToEnum<
10378
Keys extends UnknownArray,
10479
Numeric extends boolean,
105-
CamelCase_ extends boolean,
10680
> = Simplify<{readonly [
10781
K in keyof Keys as K extends `${number}`
10882
? Keys[K] extends PropertyKey
109-
? CamelCase_ extends true
110-
? CamelCase<Keys[K]>
111-
: Keys[K]
83+
? Keys[K]
11284
: never
11385
: never
11486
]: Numeric extends true

test-d/union-to-enum.ts

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {expectType} from 'tsd';
2-
import type {UnionToEnum} from '../index.d.ts';
2+
import type {CamelCasedProperties, UnionToEnum} from '../index.d.ts';
33

44
// Union input
55
expectType<UnionToEnum<'b' | 'a' | 'd' | 'c'>>({b: 'b', a: 'a', d: 'd', c: 'c'} as const);
@@ -15,17 +15,11 @@ expectType<UnionToEnum<'Only', true>>({Only: 1} as const);
1515

1616
// Tuple with numeric keys
1717
expectType<UnionToEnum<[1, 2, 3]>>({1: 1, 2: 2, 3: 3} as const);
18-
expectType<UnionToEnum<[1, 2, 3], true, {startIndex: 10}>>({1: 10, 2: 11, 3: 12} as const);
18+
expectType<UnionToEnum<[1, 2, 3], true>>({1: 1, 2: 2, 3: 3} as const);
1919

2020
// Mixed keys
2121
expectType<UnionToEnum<['a', 1, 'b']>>({a: 'a', 1: 1, b: 'b'} as const);
22-
expectType<UnionToEnum<['a', 1, 'b'], true, {startIndex: 0}>>({a: 0, 1: 1, b: 2} as const);
23-
24-
// Literal const arrays
25-
const buttons = ['Play', 'Pause', 'Stop'] as const;
26-
27-
expectType<UnionToEnum<typeof buttons>>({Play: 'Play', Pause: 'Pause', Stop: 'Stop'} as const);
28-
expectType<UnionToEnum<typeof buttons, true, {startIndex: 0}>>({Play: 0, Pause: 1, Stop: 2} as const);
22+
expectType<UnionToEnum<['a', 1, 'b'], true>>({a: 1, 1: 2, b: 3} as const);
2923

3024
// Symbol keys
3125
declare const sym1: unique symbol;
@@ -51,27 +45,28 @@ expectType<UnionToEnum<number[]>>({} as const);
5145
expectType<UnionToEnum<symbol[]>>({} as const);
5246

5347
// `never` / `any`
54-
expectType<UnionToEnum<never>>({} as const);
55-
expectType<UnionToEnum<any>>({} as const);
48+
expectType<UnionToEnum<never>>({});
49+
expectType<UnionToEnum<any>>({});
50+
51+
// Literal const arrays
52+
const buttons = ['Play', 'Pause', 'Stop'] as const;
53+
54+
expectType<UnionToEnum<typeof buttons>>({Play: 'Play', Pause: 'Pause', Stop: 'Stop'} as const);
55+
expectType<UnionToEnum<typeof buttons, true>>({Play: 1, Pause: 2, Stop: 3} as const);
5656

57-
// CamelCase
5857
const level = ['DEBUG', 'INFO', 'ERROR', 'WARNING'] as const;
59-
expectType<UnionToEnum<typeof buttons, false, {camelCase: true}>>({
60-
play: 'Play',
61-
pause: 'Pause',
62-
stop: 'Stop',
63-
} as const);
64-
expectType<UnionToEnum<typeof level, false, {camelCase: true}>>({
65-
debug: 'DEBUG',
66-
info: 'INFO',
67-
error: 'ERROR',
68-
warning: 'WARNING',
58+
59+
expectType<UnionToEnum<typeof level>>({
60+
DEBUG: 'DEBUG',
61+
INFO: 'INFO',
62+
ERROR: 'ERROR',
63+
WARNING: 'WARNING',
6964
} as const);
70-
expectType<UnionToEnum<typeof level, true, {camelCase: true}>>({
71-
debug: 1,
72-
info: 2,
73-
error: 3,
74-
warning: 4,
65+
expectType<UnionToEnum<typeof level, true>>({
66+
DEBUG: 1,
67+
INFO: 2,
68+
ERROR: 3,
69+
WARNING: 4,
7570
} as const);
7671

7772
// Dynamic Enum
@@ -81,7 +76,7 @@ const resrc = ['file', 'folder', 'link'] as const;
8176
declare function createEnum<
8277
const T extends readonly string[],
8378
const U extends readonly string[],
84-
>(x: T, y: U): UnionToEnum<`${T[number]}_${U[number]}`, false, {camelCase: true}>;
79+
>(x: T, y: U): CamelCasedProperties<UnionToEnum<`${T[number]}_${U[number]}`>>;
8580

8681
const Template = createEnum(verb, resrc);
8782

0 commit comments

Comments
 (0)