type-fest 4.30.2 → 4.32.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
@@ -42,6 +42,7 @@ export type {InvariantOf} from './source/invariant-of';
42
42
  export type {SetOptional} from './source/set-optional';
43
43
  export type {SetReadonly} from './source/set-readonly';
44
44
  export type {SetRequired} from './source/set-required';
45
+ export type {SetRequiredDeep} from './source/set-required-deep';
45
46
  export type {SetNonNullable} from './source/set-non-nullable';
46
47
  export type {ValueOf} from './source/value-of';
47
48
  export type {AsyncReturnType} from './source/async-return-type';
@@ -121,6 +122,7 @@ export type {IsNever} from './source/is-never';
121
122
  export type {IfNever} from './source/if-never';
122
123
  export type {IsUnknown} from './source/is-unknown';
123
124
  export type {IfUnknown} from './source/if-unknown';
125
+ export type {IsTuple} from './source/is-tuple';
124
126
  export type {ArrayIndices} from './source/array-indices';
125
127
  export type {ArrayValues} from './source/array-values';
126
128
  export type {ArraySlice} from './source/array-slice';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "4.30.2",
3
+ "version": "4.32.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
@@ -159,6 +159,7 @@ Click the type names for complete docs.
159
159
  - [`SetOptional`](source/set-optional.d.ts) - Create a type that makes the given keys optional.
160
160
  - [`SetReadonly`](source/set-readonly.d.ts) - Create a type that makes the given keys readonly.
161
161
  - [`SetRequired`](source/set-required.d.ts) - Create a type that makes the given keys required.
162
+ - [`SetRequiredDeep`](source/set-required-deep.d.ts) - Like `SetRequired` except it selects the keys deeply.
162
163
  - [`SetNonNullable`](source/set-non-nullable.d.ts) - Create a type that makes the given keys non-nullable.
163
164
  - [`ValueOf`](source/value-of.d.ts) - Create a union of the given object's values, and optionally specify which keys to get the values from.
164
165
  - [`ConditionalKeys`](source/conditional-keys.d.ts) - Extract keys from a shape where values extend the given `Condition` type.
@@ -247,6 +248,7 @@ type ShouldBeNever = IfAny<'not any', 'not never', 'never'>;
247
248
  - [`IsUnknown`](source/is-unknown.d.ts) - Returns a boolean for whether the given type is `unknown`. (Conditional version: [`IfUnknown`](source/if-unknown.d.ts))
248
249
  - [`IsEmptyObject`](source/empty-object.d.ts) - Returns a boolean for whether the type is strictly equal to an empty plain object, the `{}` value. (Conditional version: [`IfEmptyObject`](source/if-empty-object.d.ts))
249
250
  - [`IsNull`](source/is-null.d.ts) - Returns a boolean for whether the given type is `null`. (Conditional version: [`IfNull`](source/if-null.d.ts))
251
+ - [`IsTuple`](source/is-tuple.d.ts) - Returns a boolean for whether the given array is a tuple.
250
252
 
251
253
  ### JSON
252
254
 
@@ -367,6 +369,7 @@ type ShouldBeNever = IfAny<'not any', 'not never', 'never'>;
367
369
  - `SetElement` - See [`IterableElement`](source/iterable-element.d.ts)
368
370
  - `SetEntry` - See [`IterableElement`](source/iterable-element.d.ts)
369
371
  - `SetValues` - See [`IterableElement`](source/iterable-element.d.ts)
372
+ - `PickByTypes` - See [`ConditionalPick`](source/conditional-pick.d.ts)
370
373
 
371
374
  ## Tips
372
375
 
@@ -1048,6 +1051,7 @@ You can find some examples in the [TypeScript docs](https://www.typescriptlang.o
1048
1051
 
1049
1052
  - [Sindre Sorhus](https://github.com/sindresorhus)
1050
1053
  - [Haozheng Li](https://github.com/Emiyaaaaa)
1054
+ - [Som Shekhar Mukherjee](https://github.com/som-sm)
1051
1055
  - [Jarek Radosz](https://github.com/CvX)
1052
1056
  - [Dimitri Benin](https://github.com/BendingBender)
1053
1057
  - [Pelle Wessman](https://github.com/voxpelli)
@@ -1,3 +1,4 @@
1
+ import type {IfNever} from '../if-never';
1
2
  import type {UnknownArray} from '../unknown-array';
2
3
 
3
4
  /**
@@ -90,4 +91,36 @@ T extends readonly [...infer U] ?
90
91
  /**
91
92
  Returns whether the given array `T` is readonly.
92
93
  */
93
- export type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
94
+ export type IsArrayReadonly<T extends UnknownArray> = IfNever<T, false, T extends unknown[] ? false : true>;
95
+
96
+ /**
97
+ An if-else-like type that resolves depending on whether the given array is readonly.
98
+
99
+ @see {@link IsArrayReadonly}
100
+
101
+ @example
102
+ ```
103
+ import type {ArrayTail} from 'type-fest';
104
+
105
+ type ReadonlyPreservingArrayTail<TArray extends readonly unknown[]> =
106
+ ArrayTail<TArray> extends infer Tail
107
+ ? IfArrayReadonly<TArray, Readonly<Tail>, Tail>
108
+ : never;
109
+
110
+ type ReadonlyTail = ReadonlyPreservingArrayTail<readonly [string, number, boolean]>;
111
+ //=> readonly [number, boolean]
112
+
113
+ type NonReadonlyTail = ReadonlyPreservingArrayTail<[string, number, boolean]>;
114
+ //=> [number, boolean]
115
+
116
+ type ShouldBeTrue = IfArrayReadonly<readonly unknown[]>;
117
+ //=> true
118
+
119
+ type ShouldBeBar = IfArrayReadonly<unknown[], 'foo', 'bar'>;
120
+ //=> 'bar'
121
+ ```
122
+ */
123
+ export type IfArrayReadonly<T extends UnknownArray, TypeIfArrayReadonly = true, TypeIfNotArrayReadonly = false> =
124
+ IsArrayReadonly<T> extends infer Result
125
+ ? Result extends true ? TypeIfArrayReadonly : TypeIfNotArrayReadonly
126
+ : never; // Should never happen
@@ -1,5 +1,6 @@
1
1
  import type {Simplify} from '../simplify';
2
2
  import type {UnknownArray} from '../unknown-array';
3
+ import type {KeysOfUnion} from '../keys-of-union';
3
4
  import type {FilterDefinedKeys, FilterOptionalKeys} from './keys';
4
5
  import type {NonRecursiveType} from './type';
5
6
  import type {ToString} from './string';
@@ -80,3 +81,44 @@ export type UndefinedToOptional<T extends object> = Simplify<
80
81
  [Key in keyof Pick<T, FilterOptionalKeys<T>>]?: Exclude<T[Key], undefined>;
81
82
  }
82
83
  >;
84
+
85
+ /**
86
+ Works similar to the built-in `Pick` utility type, except for the following differences:
87
+ - Distributes over union types and allows picking keys from any member of the union type.
88
+ - Primitives types are returned as-is.
89
+ - Picks all keys if `Keys` is `any`.
90
+ - Doesn't pick `number` from a `string` index signature.
91
+
92
+ @example
93
+ ```
94
+ type ImageUpload = {
95
+ url: string;
96
+ size: number;
97
+ thumbnailUrl: string;
98
+ };
99
+
100
+ type VideoUpload = {
101
+ url: string;
102
+ duration: number;
103
+ encodingFormat: string;
104
+ };
105
+
106
+ // Distributes over union types and allows picking keys from any member of the union type
107
+ type MediaDisplay = HomomorphicPick<ImageUpload | VideoUpload, "url" | "size" | "duration">;
108
+ //=> {url: string; size: number} | {url: string; duration: number}
109
+
110
+ // Primitive types are returned as-is
111
+ type Primitive = HomomorphicPick<string | number, 'toUpperCase' | 'toString'>;
112
+ //=> string | number
113
+
114
+ // Picks all keys if `Keys` is `any`
115
+ type Any = HomomorphicPick<{a: 1; b: 2} | {c: 3}, any>;
116
+ //=> {a: 1; b: 2} | {c: 3}
117
+
118
+ // Doesn't pick `number` from a `string` index signature
119
+ type IndexSignature = HomomorphicPick<{[k: string]: unknown}, number>;
120
+ //=> {}
121
+ */
122
+ export type HomomorphicPick<T, Keys extends KeysOfUnion<T>> = {
123
+ [P in keyof T as Extract<P, Keys>]: T[P]
124
+ };
@@ -25,7 +25,7 @@ type Includes<Value extends readonly any[], Item> =
25
25
  @category Utilities
26
26
  */
27
27
  export type IsEqual<A, B> =
28
- (<G>() => G extends A ? 1 : 2) extends
29
- (<G>() => G extends B ? 1 : 2)
28
+ (<G>() => G extends A & G | G ? 1 : 2) extends
29
+ (<G>() => G extends B & G | G ? 1 : 2)
30
30
  ? true
31
31
  : false;
@@ -0,0 +1,78 @@
1
+ import type {IfAny} from './if-any';
2
+ import type {IfNever} from './if-never';
3
+ import type {UnknownArray} from './unknown-array';
4
+
5
+ /**
6
+ @see {@link IsTuple}
7
+ */
8
+ export type IsTupleOptions = {
9
+ /**
10
+ Consider only fixed length arrays as tuples.
11
+
12
+ - When set to `true` (default), arrays with rest elements (e.g., `[1, ...number[]]`) are _not_ considered as tuples.
13
+ - When set to `false`, arrays with at least one non-rest element (e.g., `[1, ...number[]]`) are considered as tuples.
14
+
15
+ @default true
16
+
17
+ @example
18
+ ```ts
19
+ import type {IsTuple} from 'type-fest';
20
+
21
+ type Example1 = IsTuple<[number, ...number[]], {fixedLengthOnly: true}>;
22
+ //=> false
23
+
24
+ type Example2 = IsTuple<[number, ...number[]], {fixedLengthOnly: false}>;
25
+ //=> true
26
+ ```
27
+ */
28
+ fixedLengthOnly?: boolean;
29
+ };
30
+
31
+ /**
32
+ Returns a boolean for whether the given array is a tuple.
33
+
34
+ Use-case:
35
+ - If you want to make a conditional branch based on the result of whether an array is a tuple or not.
36
+
37
+ Note: `IsTuple` returns `boolean` when instantiated with a union of tuple and non-tuple (e.g., `IsTuple<[1, 2] | number[]>`).
38
+
39
+ @example
40
+ ```ts
41
+ import type {IsTuple} from 'type-fest';
42
+
43
+ type Tuple = IsTuple<[1, 2, 3]>;
44
+ //=> true
45
+
46
+ type NotTuple = IsTuple<number[]>;
47
+ //=> false
48
+
49
+ type TupleWithOptionalItems = IsTuple<[1?, 2?]>;
50
+ //=> true
51
+
52
+ type RestItemsNotAllowed = IsTuple<[1, 2, ...number[]]>;
53
+ //=> false
54
+
55
+ type RestItemsAllowed = IsTuple<[1, 2, ...number[]], {fixedLengthOnly: false}>;
56
+ //=> true
57
+ ```
58
+
59
+ @see {@link IsTupleOptions}
60
+
61
+ @category Type Guard
62
+ @category Utilities
63
+ */
64
+ export type IsTuple<
65
+ TArray extends UnknownArray,
66
+ Options extends IsTupleOptions = {fixedLengthOnly: true},
67
+ > =
68
+ IfAny<TArray, boolean, IfNever<TArray, false,
69
+ TArray extends unknown // For distributing `TArray`
70
+ ? number extends TArray['length']
71
+ ? Options['fixedLengthOnly'] extends false
72
+ ? IfNever<keyof TArray & `${number}`,
73
+ TArray extends readonly [...any, any] ? true : false, // To handle cases where a non-rest element follows a rest element, e.g., `[...number[], number]`
74
+ true>
75
+ : false
76
+ : true
77
+ : false
78
+ >>;
@@ -1,7 +1,7 @@
1
1
  import type {BuiltIns} from './internal';
2
2
 
3
3
  /**
4
- @see PartialDeep
4
+ @see {@link PartialDeep}
5
5
  */
6
6
  export type PartialDeepOptions = {
7
7
  /**
@@ -10,6 +10,32 @@ export type PartialDeepOptions = {
10
10
  @default false
11
11
  */
12
12
  readonly recurseIntoArrays?: boolean;
13
+
14
+ /**
15
+ Allows `undefined` values in non-tuple arrays.
16
+
17
+ - When set to `true`, elements of non-tuple arrays can be `undefined`.
18
+ - When set to `false`, only explicitly defined elements are allowed in non-tuple arrays, ensuring stricter type checking.
19
+
20
+ @default true
21
+
22
+ @example
23
+ You can prevent `undefined` values in non-tuple arrays by passing `{recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}` as the second type argument:
24
+
25
+ ```
26
+ import type {PartialDeep} from 'type-fest';
27
+
28
+ type Settings = {
29
+ languages: string[];
30
+ };
31
+
32
+ declare const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}>;
33
+
34
+ partialSettings.languages = [undefined]; // Error
35
+ partialSettings.languages = []; // Ok
36
+ ```
37
+ */
38
+ readonly allowUndefinedInNonTupleArrays?: boolean;
13
39
  };
14
40
 
15
41
  /**
@@ -25,12 +51,12 @@ import type {PartialDeep} from 'type-fest';
25
51
 
26
52
  const settings: Settings = {
27
53
  textEditor: {
28
- fontSize: 14;
29
- fontColor: '#000000';
30
- fontWeight: 400;
31
- }
32
- autocomplete: false;
33
- autosave: true;
54
+ fontSize: 14,
55
+ fontColor: '#000000',
56
+ fontWeight: 400
57
+ },
58
+ autocomplete: false,
59
+ autosave: true
34
60
  };
35
61
 
36
62
  const applySavedSettings = (savedSettings: PartialDeep<Settings>) => {
@@ -45,7 +71,7 @@ By default, this does not affect elements in array and tuple types. You can chan
45
71
  ```
46
72
  import type {PartialDeep} from 'type-fest';
47
73
 
48
- interface Settings {
74
+ type Settings = {
49
75
  languages: string[];
50
76
  }
51
77
 
@@ -54,6 +80,8 @@ const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
54
80
  };
55
81
  ```
56
82
 
83
+ @see {@link PartialDeepOptions}
84
+
57
85
  @category Object
58
86
  @category Array
59
87
  @category Set
@@ -74,8 +102,8 @@ export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends
74
102
  ? Options['recurseIntoArrays'] extends true
75
103
  ? ItemType[] extends T // Test for arrays (non-tuples) specifically
76
104
  ? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
77
- ? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
78
- : Array<PartialDeep<ItemType | undefined, Options>>
105
+ ? ReadonlyArray<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
106
+ : Array<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
79
107
  : PartialObjectDeep<T, Options> // Tuples behave properly
80
108
  : T // If they don't opt into array testing, just use the original type
81
109
  : PartialObjectDeep<T, Options>
@@ -1,6 +1,16 @@
1
- import type {Except} from './except';
2
1
  import type {Simplify} from './simplify';
3
2
 
3
+ type SetFieldTypeOptions = {
4
+ /**
5
+ Preserve optional and readonly modifiers for properties being updated.
6
+
7
+ NOTE: Property modifiers will always be preserved for properties that are not being updated.
8
+
9
+ @default true
10
+ */
11
+ preservePropertyModifiers?: boolean;
12
+ };
13
+
4
14
  /**
5
15
  Create a type that changes the type of the given keys.
6
16
 
@@ -15,23 +25,33 @@ Use-cases:
15
25
  import type {SetFieldType} from 'type-fest';
16
26
 
17
27
  type MyModel = {
18
- id: number;
19
- createdAt: Date;
20
- updatedAt: Date;
28
+ readonly id: number;
29
+ readonly createdAt: Date;
30
+ updatedAt?: Date;
21
31
  };
22
32
 
23
33
  type MyModelApi = SetFieldType<MyModel, 'createdAt' | 'updatedAt', string>;
24
34
  // {
25
- // id: number;
26
- // createdAt: string;
27
- // updatedAt: string;
35
+ // readonly id: number;
36
+ // readonly createdAt: string;
37
+ // updatedAt?: string;
38
+ // }
39
+
40
+ // `preservePropertyModifiers` option can be set to `false` if you want to remove property modifiers for properties being updated
41
+ type MyModelApi = SetFieldType<MyModel, 'createdAt' | 'updatedAt', string, {preservePropertyModifiers: false}>;
42
+ // {
43
+ // readonly id: number;
44
+ // createdAt: string; // no longer readonly
45
+ // updatedAt: string; // no longer optional
28
46
  // }
29
47
  ```
30
48
 
31
49
  @category Object
32
50
  */
33
- export type SetFieldType<BaseType, Keys extends keyof BaseType, NewType> =
34
- Simplify<
35
- Except<BaseType, Keys> &
36
- Record<Keys, NewType>
37
- >;
51
+ export type SetFieldType<BaseType, Keys extends keyof BaseType, NewType, Options extends SetFieldTypeOptions = {preservePropertyModifiers: true}> =
52
+ Simplify<{
53
+ [P in keyof BaseType]: P extends Keys ? NewType : BaseType[P];
54
+ } & (
55
+ // `Record` is used to remove property modifiers
56
+ Options['preservePropertyModifiers'] extends false ? Record<Keys, NewType> : unknown
57
+ )>;
@@ -1,4 +1,6 @@
1
1
  import type {Except} from './except';
2
+ import type {HomomorphicPick} from './internal';
3
+ import type {KeysOfUnion} from './keys-of-union';
2
4
  import type {Simplify} from './simplify';
3
5
 
4
6
  /**
@@ -32,6 +34,6 @@ export type SetOptional<BaseType, Keys extends keyof BaseType> =
32
34
  // Pick just the keys that are readonly from the base type.
33
35
  Except<BaseType, Keys> &
34
36
  // Pick the keys that should be mutable from the base type and make them mutable.
35
- Partial<Except<BaseType, Exclude<keyof BaseType, Keys>>>
37
+ Partial<HomomorphicPick<BaseType, Keys & KeysOfUnion<BaseType>>>
36
38
  >
37
39
  : never;
@@ -1,4 +1,6 @@
1
1
  import type {Except} from './except';
2
+ import type {HomomorphicPick} from './internal';
3
+ import type {KeysOfUnion} from './keys-of-union';
2
4
  import type {Simplify} from './simplify';
3
5
 
4
6
  /**
@@ -33,6 +35,6 @@ export type SetReadonly<BaseType, Keys extends keyof BaseType> =
33
35
  BaseType extends unknown
34
36
  ? Simplify<
35
37
  Except<BaseType, Keys> &
36
- Readonly<Except<BaseType, Exclude<keyof BaseType, Keys>>>
38
+ Readonly<HomomorphicPick<BaseType, Keys & KeysOfUnion<BaseType>>>
37
39
  >
38
40
  : never;
@@ -0,0 +1,46 @@
1
+ import type {NonRecursiveType, StringToNumber} from './internal';
2
+ import type {Paths} from './paths';
3
+ import type {SimplifyDeep} from './simplify-deep';
4
+ import type {UnknownArray} from './unknown-array';
5
+
6
+ /**
7
+ Create a type that makes the given keys required. You can specify deeply nested key paths. The remaining keys are kept as is.
8
+
9
+ Use-case: Selectively make nested properties required in complex types like models.
10
+
11
+ @example
12
+ ```
13
+ import type {SetRequiredDeep} from 'type-fest';
14
+
15
+ type Foo = {
16
+ a?: number;
17
+ b?: string;
18
+ c?: {
19
+ d?: number
20
+ }[]
21
+ }
22
+
23
+ type SomeRequiredDeep = SetRequiredDeep<Foo, 'a' | `c.${number}.d`>;
24
+ // type SomeRequiredDeep = {
25
+ // a: number; // Is now required
26
+ // b?: string;
27
+ // c: {
28
+ // d: number // Is now required
29
+ // }[]
30
+ // }
31
+ ```
32
+
33
+ @category Object
34
+ */
35
+ export type SetRequiredDeep<BaseType, KeyPaths extends Paths<BaseType>> =
36
+ BaseType extends NonRecursiveType
37
+ ? BaseType
38
+ : SimplifyDeep<(
39
+ BaseType extends UnknownArray
40
+ ? {}
41
+ : {[K in keyof BaseType as K extends (KeyPaths | StringToNumber<KeyPaths & string>) ? K : never]-?: BaseType[K]}
42
+ ) & {
43
+ [K in keyof BaseType]: Extract<KeyPaths, `${K & (string | number)}.${string}`> extends never
44
+ ? BaseType[K]
45
+ : SetRequiredDeep<BaseType[K], KeyPaths extends `${K & (string | number)}.${infer Rest extends Paths<BaseType[K]>}` ? Rest : never>
46
+ }>;
@@ -1,5 +1,9 @@
1
1
  import type {Except} from './except';
2
+ import type {HomomorphicPick, IfArrayReadonly} from './internal';
3
+ import type {KeysOfUnion} from './keys-of-union';
4
+ import type {OptionalKeysOf} from './optional-keys-of';
2
5
  import type {Simplify} from './simplify';
6
+ import type {UnknownArray} from './unknown-array';
3
7
 
4
8
  /**
5
9
  Create a type that makes the given keys required. The remaining keys are kept as is. The sister of the `SetOptional` type.
@@ -22,19 +26,46 @@ type SomeRequired = SetRequired<Foo, 'b' | 'c'>;
22
26
  // b: string; // Was already required and still is.
23
27
  // c: boolean; // Is now required.
24
28
  // }
29
+
30
+ // Set specific indices in an array to be required.
31
+ type ArrayExample = SetRequired<[number?, number?, number?], 0 | 1>;
32
+ //=> [number, number, number?]
25
33
  ```
26
34
 
27
35
  @category Object
28
36
  */
29
37
  export type SetRequired<BaseType, Keys extends keyof BaseType> =
30
- // `extends unknown` is always going to be the case and is used to convert any
31
- // union into a [distributive conditional
32
- // type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
33
- BaseType extends unknown
34
- ? Simplify<
38
+ BaseType extends UnknownArray
39
+ ? SetArrayRequired<BaseType, Keys> extends infer ResultantArray
40
+ ? IfArrayReadonly<BaseType, Readonly<ResultantArray>, ResultantArray>
41
+ : never
42
+ : Simplify<
35
43
  // Pick just the keys that are optional from the base type.
36
44
  Except<BaseType, Keys> &
37
45
  // Pick the keys that should be required from the base type and make them required.
38
- Required<Except<BaseType, Exclude<keyof BaseType, Keys>>>
39
- >
40
- : never;
46
+ Required<HomomorphicPick<BaseType, Keys & KeysOfUnion<BaseType>>>
47
+ >;
48
+
49
+ /**
50
+ Remove the optional modifier from the specified keys in an array.
51
+ */
52
+ type SetArrayRequired<
53
+ TArray extends UnknownArray,
54
+ Keys,
55
+ Counter extends any[] = [],
56
+ Accumulator extends UnknownArray = [],
57
+ > = TArray extends unknown // For distributing `TArray` when it's a union
58
+ ? keyof TArray & `${number}` extends never
59
+ // Exit if `TArray` is empty (e.g., []), or
60
+ // `TArray` contains no non-rest elements preceding the rest element (e.g., `[...string[]]` or `[...string[], string]`).
61
+ ? [...Accumulator, ...TArray]
62
+ : TArray extends readonly [(infer First)?, ...infer Rest]
63
+ ? '0' extends OptionalKeysOf<TArray> // If the first element of `TArray` is optional
64
+ ? `${Counter['length']}` extends `${Keys & (string | number)}` // If the current index needs to be required
65
+ ? SetArrayRequired<Rest, Keys, [...Counter, any], [...Accumulator, First]>
66
+ // If the current element is optional, but it doesn't need to be required,
67
+ // then we can exit early, since no further elements can now be made required.
68
+ : [...Accumulator, ...TArray]
69
+ : SetArrayRequired<Rest, Keys, [...Counter, any], [...Accumulator, TArray[0]]>
70
+ : never // Should never happen, since `[(infer F)?, ...infer R]` is a top-type for arrays.
71
+ : never; // Should never happen