type-fest 5.3.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/index.d.ts +3 -0
  2. package/package.json +4 -4
  3. package/readme.md +5 -0
  4. package/source/all-extend.d.ts +9 -6
  5. package/source/array-reverse.d.ts +84 -0
  6. package/source/array-slice.d.ts +1 -1
  7. package/source/array-splice.d.ts +3 -3
  8. package/source/conditional-pick-deep.d.ts +1 -1
  9. package/source/conditional-simplify-deep.d.ts +3 -3
  10. package/source/distributed-omit.d.ts +4 -4
  11. package/source/distributed-pick.d.ts +5 -5
  12. package/source/exact.d.ts +1 -1
  13. package/source/except.d.ts +5 -5
  14. package/source/exclusify-union.d.ts +41 -7
  15. package/source/fixed-length-array.d.ts +6 -6
  16. package/source/get.d.ts +9 -3
  17. package/source/int-closed-range.d.ts +2 -2
  18. package/source/int-range.d.ts +2 -2
  19. package/source/internal/object.d.ts +25 -1
  20. package/source/is-literal.d.ts +3 -2
  21. package/source/is-never.d.ts +2 -2
  22. package/source/is-unknown.d.ts +1 -1
  23. package/source/jsonifiable.d.ts +3 -5
  24. package/source/key-as-string.d.ts +1 -1
  25. package/source/merge-deep.d.ts +7 -7
  26. package/source/merge-exclusive.d.ts +3 -3
  27. package/source/merge.d.ts +4 -1
  28. package/source/non-empty-string.d.ts +3 -3
  29. package/source/non-empty-tuple.d.ts +2 -2
  30. package/source/numeric.d.ts +3 -3
  31. package/source/object-merge.d.ts +194 -0
  32. package/source/omit-deep.d.ts +6 -22
  33. package/source/omit-index-signature.d.ts +8 -4
  34. package/source/override-properties.d.ts +1 -1
  35. package/source/package-json.d.ts +1 -1
  36. package/source/paths.d.ts +1 -1
  37. package/source/readonly-tuple.d.ts +2 -2
  38. package/source/required-deep.d.ts +2 -1
  39. package/source/schema.d.ts +10 -7
  40. package/source/set-non-nullable-deep.d.ts +1 -1
  41. package/source/set-parameter-type.d.ts +7 -7
  42. package/source/set-required-deep.d.ts +1 -7
  43. package/source/set-return-type.d.ts +1 -1
  44. package/source/split-on-rest-element.d.ts +2 -2
  45. package/source/subtract.d.ts +1 -1
  46. package/source/sum.d.ts +1 -1
  47. package/source/tuple-of.d.ts +1 -1
  48. package/source/tuple-to-object.d.ts +6 -6
  49. package/source/tuple-to-union.d.ts +1 -1
  50. package/source/union-to-intersection.d.ts +1 -1
  51. package/source/unknown-record.d.ts +6 -6
  52. package/source/unwrap-partial.d.ts +33 -0
  53. package/source/value-of.d.ts +2 -2
  54. package/source/words.d.ts +2 -2
package/index.d.ts CHANGED
@@ -22,6 +22,7 @@ export type {TaggedUnion} from './source/tagged-union.d.ts';
22
22
  export type {Writable} from './source/writable.d.ts';
23
23
  export type {WritableDeep} from './source/writable-deep.d.ts';
24
24
  export type {Merge} from './source/merge.d.ts';
25
+ export type {ObjectMerge} from './source/object-merge.d.ts';
25
26
  export type {MergeDeep, MergeDeepOptions} from './source/merge-deep.d.ts';
26
27
  export type {MergeExclusive} from './source/merge-exclusive.d.ts';
27
28
  export type {RequireAtLeastOne} from './source/require-at-least-one.d.ts';
@@ -32,6 +33,7 @@ export type {SingleKeyObject} from './source/single-key-object.d.ts';
32
33
  export type {OmitIndexSignature} from './source/omit-index-signature.d.ts';
33
34
  export type {PickIndexSignature} from './source/pick-index-signature.d.ts';
34
35
  export type {PartialDeep, PartialDeepOptions} from './source/partial-deep.d.ts';
36
+ export type {UnwrapPartial} from './source/unwrap-partial.d.ts';
35
37
  export type {RequiredDeep} from './source/required-deep.d.ts';
36
38
  export type {PickDeep} from './source/pick-deep.d.ts';
37
39
  export type {OmitDeep} from './source/omit-deep.d.ts';
@@ -164,6 +166,7 @@ export type {IsOptional} from './source/is-optional.d.ts';
164
166
  export type {IsNullable} from './source/is-nullable.d.ts';
165
167
  export type {TupleOf} from './source/tuple-of.d.ts';
166
168
  export type {ExclusifyUnion} from './source/exclusify-union.d.ts';
169
+ export type {ArrayReverse} from './source/array-reverse.d.ts';
167
170
 
168
171
  // Template literal types
169
172
  export type {CamelCase, CamelCaseOptions} from './source/camel-case.d.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "5.3.0",
3
+ "version": "5.4.0",
4
4
  "description": "A collection of essential TypeScript types",
5
5
  "license": "(MIT OR CC0-1.0)",
6
6
  "repository": "sindresorhus/type-fest",
@@ -25,9 +25,9 @@
25
25
  "node": ">=20"
26
26
  },
27
27
  "scripts": {
28
- "test:tsc": "node --max-old-space-size=5120 ./node_modules/.bin/tsc",
29
- "test:tsd": "tsd",
30
- "test:xo": "xo",
28
+ "test:tsc": "node --max-old-space-size=6144 ./node_modules/.bin/tsc",
29
+ "test:tsd": "node --max-old-space-size=6144 ./node_modules/.bin/tsd",
30
+ "test:xo": "node --max-old-space-size=6144 ./node_modules/.bin/xo",
31
31
  "test:linter": "node --test",
32
32
  "test": "run-p test:*"
33
33
  },
package/readme.md CHANGED
@@ -106,6 +106,7 @@ Click the type names for complete docs.
106
106
  - [`Writable`](source/writable.d.ts) - Create a type that strips `readonly` from the given type. Inverse of `Readonly<T>`.
107
107
  - [`WritableDeep`](source/writable-deep.d.ts) - Create a deeply mutable version of an `object`/`ReadonlyMap`/`ReadonlySet`/`ReadonlyArray` type. The inverse of `ReadonlyDeep<T>`. Use `Writable<T>` if you only need one level deep.
108
108
  - [`Merge`](source/merge.d.ts) - Merge two types into a new type. Keys of the second type overrides keys of the first type.
109
+ - [`ObjectMerge`](source/object-merge.d.ts) - Merge two object types into a new object type, where keys from the second override keys from the first.
109
110
  - [`MergeDeep`](source/merge-deep.d.ts) - Merge two objects or two arrays/tuples recursively into a new type.
110
111
  - [`MergeExclusive`](source/merge-exclusive.d.ts) - Create a type that has mutually exclusive keys.
111
112
  - [`OverrideProperties`](source/override-properties.d.ts) - Override only existing properties of the given type. Similar to `Merge`, but enforces that the original type has the properties you want to override.
@@ -122,6 +123,7 @@ Click the type names for complete docs.
122
123
  - [`PartialDeep`](source/partial-deep.d.ts) - Create a deeply optional version of another type. Use [`Partial<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype) if you only need one level deep.
123
124
  - [`PartialOnUndefinedDeep`](source/partial-on-undefined-deep.d.ts) - Create a deep version of another type where all keys accepting `undefined` type are set to optional.
124
125
  - [`UndefinedOnPartialDeep`](source/undefined-on-partial-deep.d.ts) - Create a deep version of another type where all optional keys are set to also accept `undefined`.
126
+ - [`UnwrapPartial`](source/unwrap-partial.d.ts) - Revert the `Partial` modifier on an object type.
125
127
  - [`ReadonlyDeep`](source/readonly-deep.d.ts) - Create a deeply immutable version of an `object`/`Map`/`Set`/`Array` type. Use [`Readonly<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype) if you only need one level deep.
126
128
  - [`LiteralUnion`](source/literal-union.d.ts) - Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729).
127
129
  - [`Tagged`](source/tagged.d.ts) - Create a [tagged type](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d) that can support [multiple tags](https://github.com/sindresorhus/type-fest/issues/665) and [per-tag metadata](https://medium.com/@ethanresnick/advanced-typescript-tagged-types-improved-with-type-level-metadata-5072fc125fcf). (This replaces the previous [`Opaque`](source/tagged.d.ts) type, which is now deprecated.)
@@ -263,6 +265,7 @@ Click the type names for complete docs.
263
265
  - [`SplitOnRestElement`](source/split-on-rest-element.d.ts) - Splits an array into three parts, where the first contains all elements before the rest element, the second is the [`rest`](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) element itself, and the third contains all elements after the rest element.
264
266
  - [`ExtractRestElement`](source/extract-rest-element.d.ts) - Extract the [`rest`](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) element type from an array.
265
267
  - [`ExcludeRestElement`](source/exclude-rest-element.d.ts) - Create a tuple with the [`rest`](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) element removed.
268
+ - [`ArrayReverse`](source/array-reverse.d.ts) - Reverse the order of elements in a tuple type.
266
269
 
267
270
  ### Numeric
268
271
 
@@ -474,6 +477,8 @@ There are many advanced types most users don't know about.
474
477
  // NodeConfig interface.
475
478
  new NodeAppBuilder().config({appName: 'ToDoApp'});
476
479
  ```
480
+
481
+ `Partial<T>` can be reverted with [`UnwrapPartial`](source/unwrap-partial.d.ts).
477
482
  </details>
478
483
 
479
484
  - [`Required<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype) - Make all properties in `T` required.
@@ -78,18 +78,21 @@ type D = AllExtend<[true, boolean, true], true>;
78
78
  Note: Behaviour of optional elements depend on the `exactOptionalPropertyTypes` compiler option. When the option is disabled, the target type must include `undefined` for a successful match.
79
79
 
80
80
  ```
81
+ // @exactOptionalPropertyTypes: true
81
82
  import type {AllExtend} from 'type-fest';
82
83
 
83
- // `exactOptionalPropertyTypes` enabled
84
84
  type A = AllExtend<[1?, 2?, 3?], number>;
85
85
  //=> true
86
+ ```
86
87
 
87
- // `exactOptionalPropertyTypes` disabled
88
- type B = AllExtend<[1?, 2?, 3?], number>;
89
- //=> false
88
+ ```
89
+ // @exactOptionalPropertyTypes: false
90
+ import type {AllExtend} from 'type-fest';
91
+
92
+ type A = AllExtend<[1?, 2?, 3?], number>;
93
+ //=> boolean
90
94
 
91
- // `exactOptionalPropertyTypes` disabled
92
- type C = AllExtend<[1?, 2?, 3?], number | undefined>;
95
+ type B = AllExtend<[1?, 2?, 3?], number | undefined>;
93
96
  //=> true
94
97
  ```
95
98
 
@@ -0,0 +1,84 @@
1
+ import type {If} from './if.d.ts';
2
+ import type {IsArrayReadonly} from './internal/array.d.ts';
3
+ import type {IfNotAnyOrNever, IsExactOptionalPropertyTypesEnabled} from './internal/type.d.ts';
4
+ import type {IsOptionalKeyOf} from './is-optional-key-of.d.ts';
5
+ import type {UnknownArray} from './unknown-array.d.ts';
6
+
7
+ /**
8
+ Reverse the order of elements in a tuple type.
9
+
10
+ @example
11
+ ```ts
12
+ import type {ArrayReverse} from 'type-fest';
13
+
14
+ type A = ArrayReverse<[string, number, boolean]>;
15
+ //=> [boolean, number, string]
16
+
17
+ type B = ArrayReverse<readonly [string, number, ...boolean[]]>;
18
+ //=> readonly [...boolean[], number, string]
19
+
20
+ type C = ArrayReverse<['foo', 'bar'] | readonly [1, 2, 3]>;
21
+ //=> ['bar', 'foo'] | readonly [3, 2, 1]
22
+
23
+ type D = ArrayReverse<string[]>;
24
+ //=> string[]
25
+
26
+ type E = ArrayReverse<[]>;
27
+ //=> []
28
+ ```
29
+
30
+ Note: If the tuple contains optional elements, the result will be a union of tuples, refer to the examples below:
31
+
32
+ @example
33
+ ```ts
34
+ import type {ArrayReverse} from 'type-fest';
35
+
36
+ type A = ArrayReverse<[string, number, boolean?]>;
37
+ //=> [number, string] | [boolean, number, string]
38
+
39
+ type B = ArrayReverse<[string, number?, boolean?]>;
40
+ //=> [string] | [number, string] | [boolean, number, string]
41
+
42
+ type C = ArrayReverse<[string?, number?, boolean?]>;
43
+ //=> [] | [string] | [number, string] | [boolean, number, string]
44
+
45
+ type D = ArrayReverse<[string, number?, ...boolean[]]>;
46
+ //=> [string] | [...boolean[], number, string]
47
+
48
+ type E = ArrayReverse<[string?, number?, ...boolean[]]>;
49
+ //=> [] | [string] | [...boolean[], number, string]
50
+ ```
51
+
52
+ @category Array
53
+ */
54
+ export type ArrayReverse<TArray extends UnknownArray> = IfNotAnyOrNever<TArray,
55
+ TArray extends unknown // For distributing `TArray`
56
+ ? _ArrayReverse<TArray> extends infer Result
57
+ ? If<IsArrayReadonly<TArray>, Readonly<Result>, Result>
58
+ : never // Should never happen
59
+ : never>; // Should never happen
60
+
61
+ type _ArrayReverse<
62
+ TArray extends UnknownArray,
63
+ BeforeRestAcc extends UnknownArray = [],
64
+ AfterRestAcc extends UnknownArray = [],
65
+ Result extends UnknownArray = never,
66
+ > =
67
+ keyof TArray & `${number}` extends never
68
+ // Enters this branch, if `TArray` is empty (e.g., `[]`),
69
+ // or `TArray` contains no non-rest elements preceding the rest element (e.g., `[...string[]]` or `[...string[], string]`).
70
+ ? TArray extends readonly [...infer Rest, infer Last]
71
+ ? _ArrayReverse<Rest, BeforeRestAcc, [...AfterRestAcc, Last], Result> // Accumulate elements that are present after the rest element in reverse order.
72
+ : Result | [...AfterRestAcc, ...TArray, ...BeforeRestAcc] // Add the rest element between the accumulated elements.
73
+ : TArray extends readonly [(infer First)?, ...infer Rest]
74
+ ? IsOptionalKeyOf<TArray, '0'> extends true
75
+ ? _ArrayReverse<
76
+ Rest,
77
+ [First | (If<IsExactOptionalPropertyTypesEnabled, never, undefined>), ...BeforeRestAcc], // Add `| undefined` for optional elements, if `exactOptionalPropertyTypes` is disabled.
78
+ AfterRestAcc,
79
+ Result | BeforeRestAcc
80
+ >
81
+ : _ArrayReverse<Rest, [First, ...BeforeRestAcc], AfterRestAcc, Result>
82
+ : never; // Should never happen, since `readonly [(infer First)?, ...infer Rest]` is a top-type for arrays.
83
+
84
+ export {};
@@ -45,7 +45,7 @@ function arraySlice<
45
45
  const slice = arraySlice([1, '2', {a: 3}, [4, 5]], 0, -1);
46
46
 
47
47
  type Slice = typeof slice;
48
- //=> [1, '2', { readonly a: 3; }]
48
+ //=> [1, '2', {readonly a: 3}]
49
49
 
50
50
  const value = slice[2].a;
51
51
  //=> 3
@@ -76,15 +76,15 @@ import type {ArraySplice} from 'type-fest';
76
76
 
77
77
  type SomeMonths0 = ['January', 'April', 'June'];
78
78
  type Months0 = ArraySplice<SomeMonths0, 1, 0, ['Feb', 'March']>;
79
- //=> ['January', 'Feb', 'March', 'April', 'June'];
79
+ //=> ['January', 'Feb', 'March', 'April', 'June']
80
80
 
81
81
  type SomeMonths1 = ['January', 'April', 'June'];
82
82
  type Months1 = ArraySplice<SomeMonths1, 1, 1>;
83
- //=> ['January', 'June'];
83
+ //=> ['January', 'June']
84
84
 
85
85
  type SomeMonths2 = ['January', 'Foo', 'April'];
86
86
  type Months2 = ArraySplice<SomeMonths2, 1, 1, ['Feb', 'March']>;
87
- //=> ['January', 'Feb', 'March', 'April'];
87
+ //=> ['January', 'Feb', 'March', 'April']
88
88
  ```
89
89
 
90
90
  @category Array
@@ -83,7 +83,7 @@ type StringOrBooleanPick = ConditionalPickDeep<Example, string | boolean>;
83
83
  // c: {
84
84
  // d: string;
85
85
  // e: {
86
- // h: string | boolean
86
+ // h: string | boolean;
87
87
  // };
88
88
  // j: boolean;
89
89
  // };
@@ -53,11 +53,11 @@ type TypeB = {
53
53
 
54
54
  type SimplifyDeepTypeAB = ConditionalSimplifyDeep<TypeA & TypeB, SomeComplexType1 | SomeComplexType2, object>;
55
55
  //=> {
56
- // foo: {
56
+ // foo: {
57
57
  // a: string;
58
- // b: string;
59
58
  // complexType: SomeComplexType1 & SomeComplexType2;
60
- // };
59
+ // b: string;
60
+ // };
61
61
  // }
62
62
  ```
63
63
 
@@ -34,7 +34,7 @@ if (omittedUnion.discriminant === 'A') {
34
34
 
35
35
  // @ts-expect-error
36
36
  const aValue = omittedUnion.a;
37
- //=> Error: `a` is not a property of `{discriminant: 'A' | 'B'}`
37
+ // Error: `a` is not a property of `{discriminant: 'A' | 'B'}`
38
38
  }
39
39
  ```
40
40
 
@@ -74,15 +74,15 @@ declare const omittedUnion: OmittedUnion;
74
74
 
75
75
  if (omittedUnion.discriminant === 'A') {
76
76
  const aValue = omittedUnion.a;
77
- //=> OK
77
+ // OK
78
78
 
79
79
  // @ts-expect-error
80
80
  const fooValue = omittedUnion.foo;
81
- //=> Error: `foo` is not a property of `{discriminant: 'A'; a: string}`
81
+ // Error: `foo` is not a property of `{discriminant: 'A'; a: string}`
82
82
 
83
83
  // @ts-expect-error
84
84
  const barValue = omittedUnion.bar;
85
- //=> Error: `bar` is not a property of `{discriminant: 'A'; a: string}`
85
+ // Error: `bar` is not a property of `{discriminant: 'A'; a: string}`
86
86
  }
87
87
  ```
88
88
 
@@ -25,7 +25,7 @@ type B = {
25
25
  type Union = A | B;
26
26
 
27
27
  type PickedUnion = Pick<Union, 'discriminant' | 'foo'>;
28
- //=> {discriminant: 'A' | 'B', foo: {bar: string} | {baz: string}}
28
+ //=> {discriminant: 'A' | 'B'; foo: {bar: string} | {baz: string}}
29
29
 
30
30
  declare const pickedUnion: PickedUnion;
31
31
 
@@ -36,7 +36,7 @@ if (pickedUnion.discriminant === 'A') {
36
36
 
37
37
  // @ts-expect-error
38
38
  const barValue = pickedUnion.foo.bar;
39
- //=> Error: Property 'bar' does not exist on type '{bar: string} | {baz: string}'.
39
+ // Error: Property 'bar' does not exist on type '{bar: string} | {baz: string}'.
40
40
  }
41
41
  ```
42
42
 
@@ -70,15 +70,15 @@ declare const pickedUnion: PickedUnion;
70
70
 
71
71
  if (pickedUnion.discriminant === 'A') {
72
72
  const barValue = pickedUnion.foo.bar;
73
- //=> OK
73
+ // OK
74
74
 
75
75
  // @ts-expect-error
76
76
  const extraneousValue = pickedUnion.extraneous;
77
- //=> Error: Property `extraneous` does not exist on type `Pick<A, 'discriminant' | 'foo'>`.
77
+ // Error: Property `extraneous` does not exist on type `Pick<A, 'discriminant' | 'foo'>`.
78
78
 
79
79
  // @ts-expect-error
80
80
  const bazValue = pickedUnion.foo.baz;
81
- //=> Error: `bar` is not a property of `{discriminant: 'A'; a: string}`.
81
+ // Error: `bar` is not a property of `{discriminant: 'A'; a: string}`.
82
82
  }
83
83
  ```
84
84
 
package/source/exact.d.ts CHANGED
@@ -29,7 +29,7 @@ declare function onlyAcceptName(arguments_: OnlyAcceptName): void;
29
29
  // TypeScript complains about excess properties when an object literal is provided.
30
30
  // @ts-expect-error
31
31
  onlyAcceptName({name: 'name', id: 1});
32
- //=> `id` is excess
32
+ // `id` is excess
33
33
 
34
34
  // TypeScript does not complain about excess properties when the provided value is a variable (not an object literal).
35
35
  const invalidInput = {name: 'name', id: 1};
@@ -68,14 +68,14 @@ type FooWithoutA = Except<Foo, 'a'>;
68
68
 
69
69
  // @ts-expect-error
70
70
  const fooWithoutA: FooWithoutA = {a: 1, b: '2'};
71
- //=> errors: 'a' does not exist in type '{ b: string; }'
71
+ // errors: 'a' does not exist in type '{ b: string; }'
72
72
 
73
73
  type FooWithoutB = Except<Foo, 'b', {requireExactProps: true}>;
74
- //=> {a: number} & Partial<Record<"b", never>>
74
+ //=> {a: number} & Partial<Record<'b', never>>
75
75
 
76
76
  // @ts-expect-error
77
77
  const fooWithoutB: FooWithoutB = {a: 1, b: '2'};
78
- //=> errors at 'b': Type 'string' is not assignable to type 'undefined'.
78
+ // errors at 'b': Type 'string' is not assignable to type 'undefined'.
79
79
 
80
80
  // The `Omit` utility type doesn't work when omitting specific keys from objects containing index signatures.
81
81
 
@@ -90,12 +90,12 @@ type UserData = {
90
90
 
91
91
  // `Omit` clearly doesn't behave as expected in this case:
92
92
  type PostPayload = Omit<UserData, 'email'>;
93
- //=> { [x: string]: string; [x: number]: string; }
93
+ //=> {[x: string]: string; [x: number]: string}
94
94
 
95
95
  // In situations like this, `Except` works better.
96
96
  // It simply removes the `email` key while preserving all the other keys.
97
97
  type PostPayloadFixed = Except<UserData, 'email'>;
98
- //=> { [x: string]: string; name: string; role: 'admin' | 'user'; }
98
+ //=> {[x: string]: string; name: string; role: 'admin' | 'user'}
99
99
  ```
100
100
 
101
101
  @category Object
@@ -30,13 +30,19 @@ loadConfig1({filePath: './config.json', content: '{ "name": "app" }'}); // No er
30
30
 
31
31
  // Use `ExclusifyUnion` to prevent that mistake.
32
32
  type Config = ExclusifyUnion<FileConfig | InlineConfig>;
33
- //=> {filePath: string; content?: never} | {content: string; filePath?: never}
33
+ //=> {
34
+ // filePath: string;
35
+ // content?: never;
36
+ // } | {
37
+ // content: string;
38
+ // filePath?: never;
39
+ // }
34
40
 
35
41
  declare function loadConfig2(options: Config): void;
36
42
 
37
43
  // @ts-expect-error
38
44
  loadConfig2({filePath: './config.json', content: '{ "name": "app" }'});
39
- //=> Error: Argument of type '{ filePath: string; content: string; }' is not assignable to parameter of type '{ filePath: string; content?: never; } | { content: string; filePath?: never; }'.
45
+ // Error: Argument of type '{ filePath: string; content: string; }' is not assignable to parameter of type '{ filePath: string; content?: never; } | { content: string; filePath?: never; }'.
40
46
 
41
47
  loadConfig2({filePath: './config.json'}); // Ok
42
48
 
@@ -63,7 +69,15 @@ function processPayment1(payment: CardPayment | PaypalPayment) {
63
69
  }
64
70
 
65
71
  type Payment = ExclusifyUnion<CardPayment | PaypalPayment>;
66
- //=> {amount: number; cardNumber: string; paypalId?: never} | {amount: number; paypalId: string; cardNumber?: never}
72
+ //=> {
73
+ // amount: number;
74
+ // cardNumber: string;
75
+ // paypalId?: never;
76
+ // } | {
77
+ // amount: number;
78
+ // paypalId: string;
79
+ // cardNumber?: never;
80
+ // }
67
81
 
68
82
  function processPayment2(payment: Payment) {
69
83
  const details = payment.cardNumber ?? payment.paypalId; // Ok
@@ -76,16 +90,36 @@ function processPayment2(payment: Payment) {
76
90
  import type {ExclusifyUnion} from 'type-fest';
77
91
 
78
92
  type A = ExclusifyUnion<{a: string} | {b: number}>;
79
- //=> {a: string; b?: never} | {a?: never; b: number}
93
+ //=> {a: string; b?: never} | {b: number; a?: never}
80
94
 
81
95
  type B = ExclusifyUnion<{a: string} | {b: number} | {c: boolean}>;
82
- //=> {a: string; b?: never; c?: never} | {a?: never; b: number; c?: never} | {a?: never; b?: never; c: boolean}
96
+ //=> {
97
+ // a: string;
98
+ // b?: never;
99
+ // c?: never;
100
+ // } | {
101
+ // b: number;
102
+ // a?: never;
103
+ // c?: never;
104
+ // } | {
105
+ // c: boolean;
106
+ // a?: never;
107
+ // b?: never;
108
+ // }
83
109
 
84
110
  type C = ExclusifyUnion<{a: string; b: number} | {b: string; c: number}>;
85
- //=> {a: string; b: number; c?: never} | {a?: never; b: string; c: number}
111
+ //=> {
112
+ // a: string;
113
+ // b: number;
114
+ // c?: never;
115
+ // } | {
116
+ // b: string;
117
+ // c: number;
118
+ // a?: never;
119
+ // }
86
120
 
87
121
  type D = ExclusifyUnion<{a?: 1; readonly b: 2} | {d: 4}>;
88
- //=> {a?: 1; readonly b: 2; d?: never} | {a?: never; b?: never; d: 4}
122
+ //=> {a?: 1; readonly b: 2; d?: never} | {d: 4; a?: never; b?: never}
89
123
  ```
90
124
 
91
125
  @category Object
@@ -34,7 +34,7 @@ const color: FixedLengthArray<number, 3> = [255, 128, 64];
34
34
 
35
35
  // @ts-expect-error
36
36
  color.pop();
37
- //=> Error: Property 'pop' does not exist on type 'FixedLengthArray<number, 3>'.
37
+ // Error: Property 'pop' does not exist on type 'FixedLengthArray<number, 3>'.
38
38
  ```
39
39
 
40
40
  Use-cases:
@@ -56,7 +56,7 @@ const blue = color[2];
56
56
 
57
57
  // @ts-expect-error
58
58
  const alpha = color[3];
59
- //=> Error: Property '3' does not exist on type 'FixedLengthArray<number, 3>'.
59
+ // Error: Property '3' does not exist on type 'FixedLengthArray<number, 3>'.
60
60
 
61
61
  // You can write to valid indices.
62
62
  color[0] = 128;
@@ -66,19 +66,19 @@ color[2] = 32;
66
66
  // But you cannot write to out-of-bounds indices.
67
67
  // @ts-expect-error
68
68
  color[3] = 0.5;
69
- //=> Error: Property '3' does not exist on type 'FixedLengthArray<number, 3>'.
69
+ // Error: Property '3' does not exist on type 'FixedLengthArray<number, 3>'.
70
70
 
71
71
  // @ts-expect-error
72
72
  color.push(0.5);
73
- //=> Error: Property 'push' does not exist on type 'FixedLengthArray<number, 3>'.
73
+ // Error: Property 'push' does not exist on type 'FixedLengthArray<number, 3>'.
74
74
 
75
75
  // @ts-expect-error
76
76
  color = [0, 128, 255, 0.5];
77
- //=> Error: Type '[number, number, number, number]' is not assignable to type 'FixedLengthArray<number, 3>'. Types of property 'length' are incompatible.
77
+ // Error: Type '[number, number, number, number]' is not assignable to type 'FixedLengthArray<number, 3>'. Types of property 'length' are incompatible.
78
78
 
79
79
  // @ts-expect-error
80
80
  color.length = 4;
81
- //=> Error: Cannot assign to 'length' because it is a read-only property.
81
+ // Error: Cannot assign to 'length' because it is a read-only property.
82
82
 
83
83
  function toHex([r, g, b]: readonly [number, number, number]) {
84
84
  return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
package/source/get.d.ts CHANGED
@@ -187,18 +187,24 @@ type ApiResponse = {
187
187
  };
188
188
 
189
189
  const getName = (apiResponse: ApiResponse) => get(apiResponse, 'hits.hits[0]._source.name');
190
- //=> (apiResponse: ApiResponse) => {given: string[]; family: string}[] | undefined
190
+ //=> (apiResponse: ApiResponse) => {
191
+ // given: string[];
192
+ // family: string;
193
+ // }[] | undefined
191
194
 
192
195
  // Path also supports a readonly array of strings
193
196
  const getNameWithPathArray = (apiResponse: ApiResponse) => get(apiResponse, ['hits', 'hits', '0', '_source', 'name']);
194
- //=> (apiResponse: ApiResponse) => {given: string[]; family: string}[] | undefined
197
+ //=> (apiResponse: ApiResponse) => {
198
+ // given: string[];
199
+ // family: string;
200
+ // }[] | undefined
195
201
 
196
202
  // Non-strict mode:
197
203
  type A = Get<string[], '3', {strict: false}>;
198
204
  //=> string
199
205
 
200
206
  type B = Get<Record<string, string>, 'foo', {strict: true}>;
201
- // => string | undefined
207
+ //=> string | undefined
202
208
  ```
203
209
 
204
210
  @category Object
@@ -17,8 +17,8 @@ Use-cases:
17
17
  ```
18
18
  import type {IntClosedRange} from 'type-fest';
19
19
 
20
- type Age = IntClosedRange<0, 120>;
21
- //=> 0 | 1 | 2 | ... | 119 | 120
20
+ type Age = IntClosedRange<0, 20>;
21
+ //=> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20
22
22
 
23
23
  type FontSize = IntClosedRange<10, 20>;
24
24
  //=> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20
@@ -17,8 +17,8 @@ Use-cases:
17
17
  ```
18
18
  import type {IntRange} from 'type-fest';
19
19
 
20
- type Age = IntRange<0, 120>;
21
- //=> 0 | 1 | 2 | ... | 119
20
+ type Age = IntRange<0, 20>;
21
+ //=> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19
22
22
 
23
23
  type FontSize = IntRange<10, 20>;
24
24
  //=> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19
@@ -9,7 +9,7 @@ import type {If} from '../if.d.ts';
9
9
  import type {IsNever} from '../is-never.d.ts';
10
10
  import type {FilterDefinedKeys, FilterOptionalKeys} from './keys.d.ts';
11
11
  import type {MapsSetsOrArrays, NonRecursiveType} from './type.d.ts';
12
- import type {ToString} from './string.d.ts';
12
+ import type {StringToNumber, ToString} from './string.d.ts';
13
13
 
14
14
  /**
15
15
  Create an object type with the given key `<Key>` and value `<Value>`.
@@ -265,4 +265,28 @@ export type CollapseLiterals<T> = {} extends T
265
265
  ? U
266
266
  : T;
267
267
 
268
+ /**
269
+ Normalize keys by including string and number representations wherever applicable.
270
+
271
+ @example
272
+ ```ts
273
+ type A = NormalizedKeys<0 | '1'>;
274
+ //=> 0 | '0' | 1 | '1'
275
+
276
+ type B = NormalizedKeys<string>;
277
+ //=> string | number
278
+
279
+ type C = NormalizedKeys<number>;
280
+ //=> number | `${number}`
281
+
282
+ type D = NormalizedKeys<symbol | 'foo'>;
283
+ //=> symbol | 'foo'
284
+ ```
285
+ */
286
+ export type NormalizedKeys<Keys extends PropertyKey> =
287
+ | Keys
288
+ | (string extends Keys ? number : never)
289
+ | StringToNumber<Keys & string>
290
+ | ToString<Keys & number>;
291
+
268
292
  export {};
@@ -207,7 +207,7 @@ const stringId = getId({asString: true});
207
207
 
208
208
  declare const runtimeBoolean: boolean;
209
209
  const eitherId = getId({asString: runtimeBoolean});
210
- //=> number | string
210
+ //=> string | number
211
211
  ```
212
212
 
213
213
  @category Type Guard
@@ -236,7 +236,8 @@ function get<Object_ extends Record<symbol, number>, Key extends keyof Object_>(
236
236
  }
237
237
 
238
238
  const symbolLiteral = Symbol('literal');
239
- const symbolValue = Symbol('value');
239
+ let symbolValue = Symbol('value1');
240
+ symbolValue = Symbol('value2');
240
241
 
241
242
  get({[symbolLiteral]: 1} as const, symbolLiteral);
242
243
  //=> 1
@@ -38,14 +38,14 @@ type IsTrue<T> = T extends true ? true : false;
38
38
 
39
39
  // When a distributive conditional is instantiated with `never`, the entire conditional results in `never`.
40
40
  type A = IsTrue<never>;
41
- // ^? type A = never
41
+ //=> never
42
42
 
43
43
  // If you don't want that behaviour, you can explicitly add an `IsNever` check before the distributive conditional.
44
44
  type IsTrueFixed<T> =
45
45
  IsNever<T> extends true ? false : T extends true ? true : false;
46
46
 
47
47
  type B = IsTrueFixed<never>;
48
- // ^? type B = false
48
+ //=> false
49
49
  ```
50
50
 
51
51
  @category Type Guard
@@ -12,7 +12,7 @@ Useful in type utilities, such as when dealing with unknown data from API calls.
12
12
  import type {IsUnknown} from 'type-fest';
13
13
 
14
14
  type A = IsUnknown<unknown>;
15
- //=> unknown
15
+ //=> true
16
16
 
17
17
  type B = IsUnknown<any>;
18
18
  //=> false
@@ -19,17 +19,15 @@ const error: Jsonifiable = {
19
19
  map: new Map([['a', 1]]),
20
20
  };
21
21
 
22
- JSON.stringify(error);
23
- //=> {"map": {}}
22
+ console.log(JSON.stringify(error)); // {"map": {}}
24
23
 
25
24
  const good: Jsonifiable = {
26
25
  number: 3,
27
- date: new Date(),
26
+ date: new Date('2025-12-25'),
28
27
  missing: undefined,
29
28
  };
30
29
 
31
- JSON.stringify(good);
32
- //=> {"number": 3, "date": "2022-10-17T22:22:35.920Z"}
30
+ console.log(JSON.stringify(good)); // {"number": 3, "date": "2025-12-25T00:00:00.000Z"}
33
31
  ```
34
32
 
35
33
  @category JSON
@@ -17,7 +17,7 @@ type Foo = {
17
17
  };
18
18
 
19
19
  type StringKeysOfFoo = KeyAsString<Foo>;
20
- //=> '1' | 'stringKey'
20
+ //=> 'stringKey' | '1'
21
21
  ```
22
22
 
23
23
  @category Object