type-fest 4.5.0 → 4.6.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.
package/index.d.ts CHANGED
@@ -50,6 +50,7 @@ export type {IterableElement} from './source/iterable-element';
50
50
  export type {Entry} from './source/entry';
51
51
  export type {Entries} from './source/entries';
52
52
  export type {SetReturnType} from './source/set-return-type';
53
+ export type {SetParameterType} from './source/set-parameter-type';
53
54
  export type {Asyncify} from './source/asyncify';
54
55
  export type {Simplify} from './source/simplify';
55
56
  export type {Jsonify} from './source/jsonify';
@@ -98,6 +99,8 @@ export type {IsNever} from './source/is-never';
98
99
  export type {IfNever} from './source/if-never';
99
100
  export type {IsUnknown} from './source/is-unknown';
100
101
  export type {IfUnknown} from './source/if-unknown';
102
+ export type {ArrayIndices} from './source/array-indices';
103
+ export type {ArrayValues} from './source/array-values';
101
104
 
102
105
  // Template literal types
103
106
  export type {CamelCase} from './source/camel-case';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "4.5.0",
3
+ "version": "4.6.0",
4
4
  "description": "A collection of essential TypeScript types",
5
5
  "license": "(MIT OR CC0-1.0)",
6
6
  "repository": "sindresorhus/type-fest",
package/readme.md CHANGED
@@ -154,6 +154,7 @@ Click the type names for complete docs.
154
154
  - [`Entry`](source/entry.d.ts) - Create a type that represents the type of an entry of a collection.
155
155
  - [`Entries`](source/entries.d.ts) - Create a type that represents the type of the entries of a collection.
156
156
  - [`SetReturnType`](source/set-return-type.d.ts) - Create a function type with a return type of your choice and the same parameters as the given function type.
157
+ - [`SetParameterType`](source/set-parameter-type.d.ts) - Create a function that replaces some parameters with the given parameters.
157
158
  - [`Simplify`](source/simplify.d.ts) - Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
158
159
  - [`Get`](source/get.d.ts) - Get a deeply-nested property from an object using a key path, like [Lodash's `.get()`](https://lodash.com/docs/latest#get) function.
159
160
  - [`StringKeyOf`](source/string-key-of.d.ts) - Get keys of the given type as strings.
@@ -172,6 +173,8 @@ Click the type names for complete docs.
172
173
  - [`IsEqual`](source/is-equal.d.ts) - Returns a boolean for whether the two given types are equal.
173
174
  - [`TaggedUnion`](source/tagged-union.d.ts) - Create a union of types that share a common discriminant property.
174
175
  - [`IntRange`](source/int-range.d.ts) - Generate a union of numbers.
176
+ - [`ArrayIndices`](source/array-indices.d.ts) - Provides valid indices for a constant array or tuple.
177
+ - [`ArrayValues`](source/array-values.d.ts) - Provides all values for a constant array or tuple.
175
178
 
176
179
  ### Type Guard
177
180
 
@@ -937,6 +940,7 @@ You can find some examples in the [TypeScript docs](https://www.typescriptlang.o
937
940
  ## Maintainers
938
941
 
939
942
  - [Sindre Sorhus](https://github.com/sindresorhus)
943
+ - [Haozheng Li](https://github.com/Emiyaaaaa)
940
944
  - [Jarek Radosz](https://github.com/CvX)
941
945
  - [Dimitri Benin](https://github.com/BendingBender)
942
946
  - [Pelle Wessman](https://github.com/voxpelli)
@@ -0,0 +1,23 @@
1
+ /**
2
+ Provides valid indices for a constant array or tuple.
3
+
4
+ Use-case: This type is useful when working with constant arrays or tuples and you want to enforce type-safety for accessing elements by their indices.
5
+
6
+ @example
7
+ ```
8
+ import type {ArrayIndices, ArrayValues} from 'type-fest';
9
+
10
+ const weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] as const;
11
+
12
+ type Weekday = ArrayIndices<typeof weekdays>;
13
+ type WeekdayName = ArrayValues<typeof weekdays>;
14
+
15
+ const getWeekdayName = (day: Weekday): WeekdayName => weekdays[day];
16
+ ```
17
+
18
+ @see {@link ArrayValues}
19
+
20
+ @category Array
21
+ */
22
+ export type ArrayIndices<Element extends readonly unknown[]> =
23
+ Exclude<Partial<Element>['length'], Element['length']>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ Provides all values for a constant array or tuple.
3
+
4
+ Use-case: This type is useful when working with constant arrays or tuples and you want to enforce type-safety with their values.
5
+
6
+ @example
7
+ ```
8
+ import type {ArrayValues, ArrayIndices} from 'type-fest';
9
+
10
+ const weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] as const;
11
+
12
+ type WeekdayName = ArrayValues<typeof weekdays>;
13
+ type Weekday = ArrayIndices<typeof weekdays>;
14
+
15
+ const getWeekdayName = (day: Weekday): WeekdayName => weekdays[day];
16
+ ```
17
+
18
+ @see {@link ArrayIndices}
19
+
20
+ @category Array
21
+ */
22
+ export type ArrayValues<T extends readonly unknown[]> = T[number];
@@ -13,16 +13,26 @@ const array = ['foo', 2];
13
13
 
14
14
  typeof lastOf(array);
15
15
  //=> number
16
+
17
+ const array = ['foo', 2] as const;
18
+
19
+ typeof lastOf(array);
20
+ //=> 2
16
21
  ```
17
22
 
18
23
  @category Array
19
24
  @category Template literal
20
25
  */
21
- export type LastArrayElement<Elements extends readonly unknown[]>
22
- = number extends Elements['length']
23
- ? Elements extends ReadonlyArray<infer Element>
24
- ? Element
25
- : never
26
- : Elements extends readonly [...any, infer Target]
27
- ? Target
28
- : never;
26
+ export type LastArrayElement<Elements extends readonly unknown[], ElementBeforeTailingSpreadElement = never> =
27
+ // If the last element of an array is a spread element, the `LastArrayElement` result should be `'the type of the element before the spread element' | 'the type of the spread element'`.
28
+ Elements extends readonly []
29
+ ? ElementBeforeTailingSpreadElement
30
+ : Elements extends readonly [...infer U, infer V]
31
+ ? V
32
+ : Elements extends readonly [infer U, ...infer V]
33
+ // If we return `V[number] | U` directly, it would be wrong for `[[string, boolean, object, ...number[]]`.
34
+ // So we need to recurse type `V` and carry over the type of the element before the spread element.
35
+ ? LastArrayElement<V, U>
36
+ : Elements extends ReadonlyArray<infer U>
37
+ ? U | ElementBeforeTailingSpreadElement
38
+ : never;
@@ -59,7 +59,7 @@ const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
59
59
  @category Set
60
60
  @category Map
61
61
  */
62
- export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIns
62
+ export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIns | (((...arguments_: any[]) => unknown)) | (new (...arguments_: any[]) => unknown)
63
63
  ? T
64
64
  : T extends Map<infer KeyType, infer ValueType>
65
65
  ? PartialMapDeep<KeyType, ValueType, Options>
@@ -69,19 +69,17 @@ export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends
69
69
  ? PartialReadonlyMapDeep<KeyType, ValueType, Options>
70
70
  : T extends ReadonlySet<infer ItemType>
71
71
  ? PartialReadonlySetDeep<ItemType, Options>
72
- : T extends ((...arguments_: any[]) => unknown)
73
- ? T | undefined
74
- : T extends object
75
- ? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
76
- ? Options['recurseIntoArrays'] extends true
77
- ? ItemType[] extends T // Test for arrays (non-tuples) specifically
78
- ? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
79
- ? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
80
- : Array<PartialDeep<ItemType | undefined, Options>>
81
- : PartialObjectDeep<T, Options> // Tuples behave properly
82
- : T // If they don't opt into array testing, just use the original type
83
- : PartialObjectDeep<T, Options>
84
- : unknown;
72
+ : T extends object
73
+ ? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
74
+ ? Options['recurseIntoArrays'] extends true
75
+ ? ItemType[] extends T // Test for arrays (non-tuples) specifically
76
+ ? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
77
+ ? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
78
+ : Array<PartialDeep<ItemType | undefined, Options>>
79
+ : PartialObjectDeep<T, Options> // Tuples behave properly
80
+ : T // If they don't opt into array testing, just use the original type
81
+ : PartialObjectDeep<T, Options>
82
+ : unknown;
85
83
 
86
84
  /**
87
85
  Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`.
@@ -38,28 +38,30 @@ Note that types containing overloaded functions are not made deeply readonly due
38
38
  */
39
39
  export type ReadonlyDeep<T> = T extends BuiltIns
40
40
  ? T
41
- : T extends (...arguments_: any[]) => unknown
42
- ? {} extends ReadonlyObjectDeep<T>
43
- ? T
44
- : HasMultipleCallSignatures<T> extends true
41
+ : T extends new (...args: any[]) => unknown
42
+ ? T // Skip class constructors
43
+ : T extends (...arguments_: any[]) => unknown
44
+ ? {} extends ReadonlyObjectDeep<T>
45
45
  ? T
46
- : ((...arguments_: Parameters<T>) => ReturnType<T>) & ReadonlyObjectDeep<T>
47
- : T extends Readonly<ReadonlyMap<infer KeyType, infer ValueType>>
48
- ? ReadonlyMapDeep<KeyType, ValueType>
49
- : T extends Readonly<ReadonlySet<infer ItemType>>
50
- ? ReadonlySetDeep<ItemType>
51
- : // Identify tuples to avoid converting them to arrays inadvertently; special case `readonly [...never[]]`, as it emerges undesirably from recursive invocations of ReadonlyDeep below.
52
- T extends readonly [] | readonly [...never[]]
53
- ? readonly []
54
- : T extends readonly [infer U, ...infer V]
55
- ? readonly [ReadonlyDeep<U>, ...ReadonlyDeep<V>]
56
- : T extends readonly [...infer U, infer V]
57
- ? readonly [...ReadonlyDeep<U>, ReadonlyDeep<V>]
58
- : T extends ReadonlyArray<infer ItemType>
59
- ? ReadonlyArray<ReadonlyDeep<ItemType>>
60
- : T extends object
61
- ? ReadonlyObjectDeep<T>
62
- : unknown;
46
+ : HasMultipleCallSignatures<T> extends true
47
+ ? T
48
+ : ((...arguments_: Parameters<T>) => ReturnType<T>) & ReadonlyObjectDeep<T>
49
+ : T extends Readonly<ReadonlyMap<infer KeyType, infer ValueType>>
50
+ ? ReadonlyMapDeep<KeyType, ValueType>
51
+ : T extends Readonly<ReadonlySet<infer ItemType>>
52
+ ? ReadonlySetDeep<ItemType>
53
+ : // Identify tuples to avoid converting them to arrays inadvertently; special case `readonly [...never[]]`, as it emerges undesirably from recursive invocations of ReadonlyDeep below.
54
+ T extends readonly [] | readonly [...never[]]
55
+ ? readonly []
56
+ : T extends readonly [infer U, ...infer V]
57
+ ? readonly [ReadonlyDeep<U>, ...ReadonlyDeep<V>]
58
+ : T extends readonly [...infer U, infer V]
59
+ ? readonly [...ReadonlyDeep<U>, ReadonlyDeep<V>]
60
+ : T extends ReadonlyArray<infer ItemType>
61
+ ? ReadonlyArray<ReadonlyDeep<ItemType>>
62
+ : T extends object
63
+ ? ReadonlyObjectDeep<T>
64
+ : unknown;
63
65
 
64
66
  /**
65
67
  Same as `ReadonlyDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `ReadonlyDeep`.
@@ -0,0 +1,68 @@
1
+ import type {IsUnknown} from './is-unknown';
2
+
3
+ /**
4
+ Create a tuple that replaces the given `Tuple`'s elements with the given `Record_`'s values at the given indices.
5
+ */
6
+ type MergeObjectToTuple<Tuple extends unknown[], Record_ extends Record<number, unknown>> = {
7
+ [K in keyof Tuple]: Record_ extends Record<string, unknown>
8
+ // Handle object case like `{0: string, 1: number}`
9
+ ? K extends `${infer NumberK extends number}`
10
+ ? NumberK extends keyof Record_ ? Record_[K] : Tuple[K]
11
+ : never // Should not happen
12
+ // Handle tuple case like `[string, number]`
13
+ : K extends keyof Record_ ? Record_[K] : Tuple[K]
14
+ };
15
+
16
+ /**
17
+ Create a function that replaces some parameters with the given parameters.
18
+
19
+ The parameters that are not specified will be kept as-is.
20
+
21
+ Note:
22
+ - This type will ignore the given function's generic type.
23
+ - If you change the parameter type that return type depends on, the return type will not change:
24
+ ```
25
+ const fn = (a: number) => a;
26
+ //=> fn: (a: number) => number;
27
+
28
+ // We change type of `a` to `string`, but return type is still `number`.
29
+ type Fn = SetParameterType<typeof fn, {0: string}>;
30
+ //=> (a: string) => number;
31
+ ```
32
+
33
+ Use-case:
34
+ - Define a wrapped function that receives something different while returning the same type.
35
+ - Mocking and testing.
36
+ - Overload function type. (See example)
37
+
38
+ @example
39
+ ```
40
+ import type {SetParameterType} from 'type-fest';
41
+
42
+ type HandleMessage = (data: Data, message: string) => void;
43
+
44
+ type HandleOk = SetParameterType<HandleMessage, {0: SuccessData, 1: 'ok'}>;
45
+ //=> type HandleOk = (data: SuccessData, message: 'ok') => void;
46
+
47
+ // Another way to define the parameters to replace.
48
+ type HandleError = SetParameterType<HandleMessage, [data: ErrorData, message: 'error']>;
49
+ //=> type HandleError = (data: ErrorData, message: 'error') => void;
50
+
51
+ // Could change single parameter type.
52
+ type HandleWarn = SetParameterType<HandleMessage, {1: 'warn'}>;
53
+ //=> type HandleWarn = (data: Data, message: 'warn') => void;
54
+ ```
55
+
56
+ @category Function
57
+ */
58
+ export type SetParameterType<Fn extends (...arguments_: any[]) => unknown, P extends Record<number, unknown>> =
59
+ // Just using `Parameters<Fn>` isn't ideal because it doesn't handle the `this` fake parameter.
60
+ Fn extends (this: infer ThisArg, ...arguments_: infer Arguments) => unknown
61
+ ? (
62
+ // If a function did not specify the `this` fake parameter, it will be inferred to `unknown`.
63
+ // We want to detect this situation just to display a friendlier type upon hovering on an IntelliSense-powered IDE.
64
+ IsUnknown<ThisArg> extends true
65
+ ? (...arguments_: MergeObjectToTuple<Arguments, P>) => ReturnType<Fn>
66
+ : (this: ThisArg, ...arguments_: MergeObjectToTuple<Arguments, P>) => ReturnType<Fn>
67
+ )
68
+ : Fn; // This part should be unreachable
@@ -38,23 +38,31 @@ export type WritableDeep<T> = T extends BuiltIns
38
38
  : HasMultipleCallSignatures<T> extends true
39
39
  ? T
40
40
  : ((...arguments_: Parameters<T>) => ReturnType<T>) & WritableObjectDeep<T>
41
- : T extends Readonly<ReadonlyMap<infer KeyType, infer ValueType>>
42
- ? WritableMapDeep<KeyType, ValueType>
43
- : T extends Readonly<ReadonlySet<infer ItemType>>
44
- ? WritableSetDeep<ItemType>
45
- : T extends object
46
- ? WritableObjectDeep<T>
47
- : unknown;
41
+ : T extends ReadonlyMap<unknown, unknown>
42
+ ? WritableMapDeep<T>
43
+ : T extends ReadonlySet<unknown>
44
+ ? WritableSetDeep<T>
45
+ : T extends readonly unknown[]
46
+ ? WritableArrayDeep<T>
47
+ : T extends object
48
+ ? WritableObjectDeep<T>
49
+ : unknown;
48
50
 
49
51
  /**
50
52
  Same as `WritableDeep`, but accepts only `Map`s as inputs. Internal helper for `WritableDeep`.
51
53
  */
52
- type WritableMapDeep<KeyType, ValueType> = {} & Writable<Map<WritableDeep<KeyType>, WritableDeep<ValueType>>>;
54
+ type WritableMapDeep<MapType extends ReadonlyMap<unknown, unknown>> =
55
+ MapType extends ReadonlyMap<infer KeyType, infer ValueType>
56
+ ? Map<WritableDeep<KeyType>, WritableDeep<ValueType>>
57
+ : MapType; // Should not heppen
53
58
 
54
59
  /**
55
60
  Same as `WritableDeep`, but accepts only `Set`s as inputs. Internal helper for `WritableDeep`.
56
61
  */
57
- type WritableSetDeep<ItemType> = {} & Writable<Set<WritableDeep<ItemType>>>;
62
+ type WritableSetDeep<SetType extends ReadonlySet<unknown>> =
63
+ SetType extends ReadonlySet<infer ItemType>
64
+ ? Set<WritableDeep<ItemType>>
65
+ : SetType; // Should not heppen
58
66
 
59
67
  /**
60
68
  Same as `WritableDeep`, but accepts only `object`s as inputs. Internal helper for `WritableDeep`.
@@ -62,3 +70,15 @@ Same as `WritableDeep`, but accepts only `object`s as inputs. Internal helper fo
62
70
  type WritableObjectDeep<ObjectType extends object> = {
63
71
  -readonly [KeyType in keyof ObjectType]: WritableDeep<ObjectType[KeyType]>
64
72
  };
73
+
74
+ /**
75
+ Same as `WritableDeep`, but accepts only `Array`s as inputs. Internal helper for `WritableDeep`.
76
+ */
77
+ type WritableArrayDeep<ArrayType extends readonly unknown[]> =
78
+ ArrayType extends readonly [] ? []
79
+ : ArrayType extends readonly [...infer U, infer V] ? [...WritableArrayDeep<U>, WritableDeep<V>]
80
+ : ArrayType extends readonly [infer U, ...infer V] ? [WritableDeep<U>, ...WritableArrayDeep<V>]
81
+ : ArrayType extends ReadonlyArray<infer U> ? Array<WritableDeep<U>>
82
+ : ArrayType extends Array<infer U> ? Array<WritableDeep<U>>
83
+ : ArrayType;
84
+