type-fest 5.4.3 → 5.5.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 (40) hide show
  1. package/index.d.ts +7 -0
  2. package/package.json +1 -1
  3. package/readme.md +14 -4
  4. package/source/all-extend.d.ts +5 -6
  5. package/source/and-all.d.ts +76 -0
  6. package/source/and.d.ts +3 -2
  7. package/source/array-length.d.ts +36 -0
  8. package/source/array-splice.d.ts +2 -2
  9. package/source/conditional-pick-deep.d.ts +5 -3
  10. package/source/conditional-pick.d.ts +6 -4
  11. package/source/exclude-exactly.d.ts +57 -0
  12. package/source/greater-than-or-equal.d.ts +34 -1
  13. package/source/greater-than.d.ts +34 -1
  14. package/source/internal/array.d.ts +0 -7
  15. package/source/internal/tuple.d.ts +1 -1
  16. package/source/internal/type.d.ts +1 -0
  17. package/source/is-equal.d.ts +0 -1
  18. package/source/is-union.d.ts +2 -1
  19. package/source/less-than-or-equal.d.ts +39 -3
  20. package/source/less-than.d.ts +35 -3
  21. package/source/merge.d.ts +25 -0
  22. package/source/omit-deep.d.ts +1 -2
  23. package/source/optional.d.ts +31 -0
  24. package/source/or-all.d.ts +73 -0
  25. package/source/or.d.ts +3 -10
  26. package/source/package-json.d.ts +2 -2
  27. package/source/paths.d.ts +40 -57
  28. package/source/pick-deep.d.ts +6 -21
  29. package/source/set-non-nullable.d.ts +3 -10
  30. package/source/set-optional.d.ts +1 -5
  31. package/source/set-parameter-type.d.ts +2 -2
  32. package/source/set-readonly.d.ts +1 -5
  33. package/source/set-required.d.ts +1 -5
  34. package/source/shared-union-fields-deep.d.ts +1 -1
  35. package/source/some-extend.d.ts +113 -0
  36. package/source/spread.d.ts +1 -5
  37. package/source/tagged.d.ts +2 -2
  38. package/source/union-member.d.ts +65 -0
  39. package/source/union-to-tuple.d.ts +4 -17
  40. package/source/writable.d.ts +1 -5
package/source/merge.d.ts CHANGED
@@ -12,6 +12,31 @@ type SimpleMerge<Destination, Source> = Simplify<{
12
12
  /**
13
13
  Merge two types into a new type. Keys of the second type overrides keys of the first type.
14
14
 
15
+ This is different from the TypeScript `&` (intersection) operator. With `&`, conflicting property types are intersected, which often results in `never`. For example, `{a: string} & {a: number}` makes `a` become `string & number`, which resolves to `never`. With `Merge`, the second type's keys cleanly override the first, so `Merge<{a: string}, {a: number}>` gives `{a: number}` as expected. `Merge` also produces a flattened type (via `Simplify`), making it more readable in IDE tooltips compared to `A & B`.
16
+
17
+ @example
18
+ ```
19
+ import type {Merge} from 'type-fest';
20
+
21
+ type Foo = {
22
+ a: string;
23
+ b: number;
24
+ };
25
+
26
+ type Bar = {
27
+ a: number; // Conflicts with Foo['a']
28
+ c: boolean;
29
+ };
30
+
31
+ // With `&`, `a` becomes `string & number` which is `never`. Not what you want.
32
+ type WithIntersection = (Foo & Bar)['a'];
33
+ //=> never
34
+
35
+ // With `Merge`, `a` is cleanly overridden to `number`.
36
+ type WithMerge = Merge<Foo, Bar>['a'];
37
+ //=> number
38
+ ```
39
+
15
40
  @example
16
41
  ```
17
42
  import type {Merge} from 'type-fest';
@@ -5,7 +5,6 @@ import type {IsNever} from './is-never.d.ts';
5
5
  import type {LiteralUnion} from './literal-union.d.ts';
6
6
  import type {Paths} from './paths.d.ts';
7
7
  import type {SimplifyDeep} from './simplify-deep.d.ts';
8
- import type {Simplify} from './simplify.d.ts';
9
8
  import type {UnionToTuple} from './union-to-tuple.d.ts';
10
9
  import type {UnknownArray} from './unknown-array.d.ts';
11
10
 
@@ -119,7 +118,7 @@ P extends `${infer RecordKeyInPath}.${infer SubPath}`
119
118
  ? IsNever<Key> extends true
120
119
  ? ObjectT
121
120
  : Key extends PropertyKey
122
- ? Simplify<Omit<ObjectT, Key>> // `Simplify` to prevent `Omit` from appearing in the resulting type
121
+ ? Omit<ObjectT, Key>
123
122
  : ObjectT
124
123
  : ObjectT;
125
124
 
@@ -0,0 +1,31 @@
1
+ /**
2
+ Create a type that represents either the value or `undefined`, while stripping `null` from the type.
3
+
4
+ Use-cases:
5
+ - Enforcing the practice of using `undefined` instead of `null` as the "absence of value" marker.
6
+ - Converting APIs that return `null` (DOM, JSON, legacy libraries) to use `undefined` consistently.
7
+
8
+ @example
9
+ ```
10
+ import type {Optional} from 'type-fest';
11
+
12
+ // Adds `undefined` to the type
13
+ type MaybeNumber = Optional<number>;
14
+ //=> number | undefined
15
+
16
+ // Strips `null` from the type
17
+ type NullableString = Optional<string | null>;
18
+ //=> string | undefined
19
+
20
+ type Config = {
21
+ name: string;
22
+ description: Optional<string>;
23
+ //=> string | undefined
24
+ };
25
+ ```
26
+
27
+ @category Utilities
28
+ */
29
+ export type Optional<Value> = Exclude<Value, null> | undefined;
30
+
31
+ export {};
@@ -0,0 +1,73 @@
1
+ import type {SomeExtend} from './some-extend.d.ts';
2
+
3
+ /**
4
+ Returns a boolean for whether any of the given elements is `true`.
5
+
6
+ Use-cases:
7
+ - Check if at least one condition in a list of booleans is met.
8
+
9
+ @example
10
+ ```
11
+ import type {OrAll} from 'type-fest';
12
+
13
+ type FFT = OrAll<[false, false, true]>;
14
+ //=> true
15
+
16
+ type FFF = OrAll<[false, false, false]>;
17
+ //=> false
18
+ ```
19
+
20
+ Note: When `boolean` is passed as an element, it is distributed into separate cases, and the final result is a union of those cases.
21
+ For example, `OrAll<[false, boolean]>` expands to `OrAll<[false, true]> | OrAll<[false, false]>`, which simplifies to `true | false` (i.e., `boolean`).
22
+
23
+ @example
24
+ ```
25
+ import type {OrAll} from 'type-fest';
26
+
27
+ type A = OrAll<[false, boolean]>;
28
+ //=> boolean
29
+
30
+ type B = OrAll<[true, boolean]>;
31
+ //=> true
32
+ ```
33
+
34
+ Note: If `never` is passed as an element, it is treated as `false` and the result is computed accordingly.
35
+
36
+ @example
37
+ ```
38
+ import type {OrAll} from 'type-fest';
39
+
40
+ type A = OrAll<[never, never, true]>;
41
+ //=> true
42
+
43
+ type B = OrAll<[never, never, false]>;
44
+ //=> false
45
+
46
+ type C = OrAll<[never, never, never]>;
47
+ //=> false
48
+
49
+ type D = OrAll<[never, never, boolean]>;
50
+ //=> boolean
51
+ ```
52
+
53
+ Note: If `any` is passed as an element, it is treated as `boolean` and the result is computed accordingly.
54
+
55
+ @example
56
+ ```
57
+ import type {OrAll} from 'type-fest';
58
+
59
+ type A = OrAll<[false, any]>;
60
+ //=> boolean
61
+
62
+ type B = OrAll<[true, any]>;
63
+ //=> true
64
+ ```
65
+
66
+ Note: `OrAll<[]>` evaluates to `false` because there are no `true` elements in an empty tuple. See [Wikipedia: Clause (logic) > Empty clauses](https://en.wikipedia.org/wiki/Clause_(logic)#Empty_clauses:~:text=The%20truth%20evaluation%20of%20an%20empty%20disjunctive%20clause%20is%20always%20false.).
67
+
68
+ @see {@link Or}
69
+ @see {@link AndAll}
70
+ */
71
+ export type OrAll<T extends readonly boolean[]> = SomeExtend<T, true>;
72
+
73
+ export {};
package/source/or.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import type {If} from './if.d.ts';
2
- import type {IsNever} from './is-never.d.ts';
1
+ import type {OrAll} from './or-all.d.ts';
3
2
 
4
3
  /**
5
4
  Returns a boolean for whether either of two given types is true.
@@ -74,16 +73,10 @@ type G = Or<never, never>;
74
73
  //=> false
75
74
  ```
76
75
 
76
+ @see {@link OrAll}
77
77
  @see {@link And}
78
78
  @see {@link Xor}
79
79
  */
80
- export type Or<A extends boolean, B extends boolean> =
81
- _Or<If<IsNever<A>, false, A>, If<IsNever<B>, false, B>>; // `never` is treated as `false`
82
-
83
- export type _Or<A extends boolean, B extends boolean> = A extends true
84
- ? true
85
- : B extends true
86
- ? true
87
- : false;
80
+ export type Or<A extends boolean, B extends boolean> = OrAll<[A, B]>;
88
81
 
89
82
  export {};
@@ -1,5 +1,5 @@
1
- import type {LiteralUnion} from './literal-union.d.ts';
2
1
  import type {JsonObject, JsonValue} from './json-value.d.ts';
2
+ import type {LiteralUnion} from './literal-union.d.ts';
3
3
 
4
4
  export namespace PackageJson {
5
5
  /**
@@ -526,7 +526,7 @@ export namespace PackageJson {
526
526
  Engines that this package runs on.
527
527
  */
528
528
  engines?: {
529
- [EngineName in 'npm' | 'node' | string]?: string;
529
+ [EngineName in LiteralUnion<'npm' | 'node', string>]?: string;
530
530
  };
531
531
 
532
532
  /**
package/source/paths.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type {StaticPartOfArray, VariablePartOfArray, NonRecursiveType, ToString, IsNumberLike, ApplyDefaultOptions} from './internal/index.d.ts';
1
+ import type {NonRecursiveType, ToString, IsNumberLike, ApplyDefaultOptions, MapsSetsOrArrays} from './internal/index.d.ts';
2
2
  import type {IsAny} from './is-any.d.ts';
3
3
  import type {UnknownArray} from './unknown-array.d.ts';
4
4
  import type {GreaterThan} from './greater-than.d.ts';
@@ -192,67 +192,50 @@ open('listB.1'); // TypeError. Because listB only has one element.
192
192
  export type Paths<T, Options extends PathsOptions = {}> = _Paths<T, ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, Options>>;
193
193
 
194
194
  type _Paths<T, Options extends Required<PathsOptions>, CurrentDepth extends number = 0> =
195
- T extends NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
195
+ T extends NonRecursiveType | Exclude<MapsSetsOrArrays, UnknownArray>
196
196
  ? never
197
197
  : IsAny<T> extends true
198
198
  ? never
199
- : T extends UnknownArray
200
- ? number extends T['length']
201
- // We need to handle the fixed and non-fixed index part of the array separately.
202
- ? InternalPaths<StaticPartOfArray<T>, Options, CurrentDepth> | InternalPaths<Array<VariablePartOfArray<T>[number]>, Options, CurrentDepth>
203
- : InternalPaths<T, Options, CurrentDepth>
204
- : T extends object
205
- ? InternalPaths<T, Options, CurrentDepth>
206
- : never;
199
+ : T extends object
200
+ ? InternalPaths<Required<T>, Options, CurrentDepth>
201
+ : never;
207
202
 
208
203
  type InternalPaths<T, Options extends Required<PathsOptions>, CurrentDepth extends number> =
209
- Options['maxRecursionDepth'] extends infer MaxDepth extends number
210
- ? Required<T> extends infer T
211
- ? T extends readonly []
212
- ? never
213
- : IsNever<keyof T> extends true // Check for empty object
214
- ? never
215
- : {
216
- [Key in keyof T]:
217
- Key extends string | number // Limit `Key` to string or number.
218
- ? (
219
- And<Options['bracketNotation'], IsNumberLike<Key>> extends true
220
- ? `[${Key}]`
221
- // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
222
- : CurrentDepth extends 0
223
- ? Key | ToString<Key>
224
- : `.${(Key | ToString<Key>)}`
225
- ) extends infer TranformedKey extends string | number ?
226
- // 1. If style is 'a[0].b' and 'Key' is a numberlike value like 3 or '3', transform 'Key' to `[${Key}]`, else to `${Key}` | Key
227
- // 2. If style is 'a.0.b', transform 'Key' to `${Key}` | Key
228
- | ((Options['leavesOnly'] extends true
229
- ? MaxDepth extends CurrentDepth
230
- ? TranformedKey
231
- : T[Key] extends infer Value
232
- ? (Value extends readonly [] | NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
233
- ? TranformedKey
234
- : IsNever<keyof Value> extends true // Check for empty object
235
- ? TranformedKey
236
- : never)
237
- : never
238
- : TranformedKey
239
- ) extends infer _TransformedKey
240
- // If `depth` is provided, the condition becomes truthy only when it reaches `CurrentDepth`.
241
- // Otherwise, since `depth` defaults to `number`, the condition is always truthy, returning paths at all depths.
242
- ? CurrentDepth extends Options['depth']
243
- ? _TransformedKey
244
- : never
245
- : never)
246
- | (
247
- // Recursively generate paths for the current key
248
- GreaterThan<MaxDepth, CurrentDepth> extends true // Limit the depth to prevent infinite recursion
249
- ? `${TranformedKey}${_Paths<T[Key], Options, Sum<CurrentDepth, 1>> & (string | number)}`
250
- : never
251
- )
252
- : never
253
- : never
254
- }[keyof T & (T extends UnknownArray ? number : unknown)]
204
+ {[Key in keyof T]: Key extends string | number // Limit `Key` to `string | number`
205
+ ? (
206
+ And<Options['bracketNotation'], IsNumberLike<Key>> extends true
207
+ ? `[${Key}]`
208
+ : CurrentDepth extends 0
209
+ // Return both `Key` and `ToString<Key>` because for number keys, like `1`, both `1` and `'1'` are valid keys.
210
+ ? Key | ToString<Key>
211
+ : `.${(Key | ToString<Key>)}`
212
+ ) extends infer TransformedKey extends string | number
213
+ ? ((Options['leavesOnly'] extends true
214
+ ? Options['maxRecursionDepth'] extends CurrentDepth
215
+ ? TransformedKey
216
+ : IsNever<T[Key]> extends true
217
+ ? TransformedKey
218
+ : T[Key] extends infer Value // For distributing `T[Key]`
219
+ ? (Value extends readonly [] | NonRecursiveType | Exclude<MapsSetsOrArrays, UnknownArray>
220
+ ? TransformedKey
221
+ : IsNever<keyof Value> extends true // Check for empty object & `unknown`, because `keyof unknown` is `never`.
222
+ ? TransformedKey
223
+ : never)
224
+ : never // Should never happen
225
+ : TransformedKey
226
+ ) extends infer _TransformedKey
227
+ // If `depth` is provided, the condition becomes truthy only when it matches `CurrentDepth`.
228
+ // Otherwise, since `depth` defaults to `number`, the condition is always truthy, returning paths at all depths.
229
+ ? CurrentDepth extends Options['depth']
230
+ ? _TransformedKey
231
+ : never
232
+ : never)
233
+ // Recursively generate paths for the current key
234
+ | (GreaterThan<Options['maxRecursionDepth'], CurrentDepth> extends true // Limit the depth to prevent infinite recursion
235
+ ? `${TransformedKey}${_Paths<T[Key], Options, Sum<CurrentDepth, 1>> & (string | number)}`
236
+ : never)
255
237
  : never
256
- : never;
238
+ : never
239
+ }[keyof T & (T extends UnknownArray ? number : unknown)];
257
240
 
258
241
  export {};
@@ -5,6 +5,7 @@ import type {Paths} from './paths.d.ts';
5
5
  import type {Simplify} from './simplify.d.ts';
6
6
  import type {UnionToIntersection} from './union-to-intersection.d.ts';
7
7
  import type {UnknownArray} from './unknown-array.d.ts';
8
+ import type {SimplifyDeep} from './simplify-deep.d.ts';
8
9
 
9
10
  /**
10
11
  Pick properties from a deeply-nested object.
@@ -36,24 +37,15 @@ type Configuration = {
36
37
  };
37
38
 
38
39
  type NameConfig = PickDeep<Configuration, 'userConfig.name'>;
39
- // type NameConfig = {
40
- // userConfig: {
41
- // name: string;
42
- // }
43
- // };
40
+ //=> {userConfig: {name: string}}
44
41
 
45
42
  // Supports optional properties
46
43
  type User = PickDeep<PartialDeep<Configuration>, 'userConfig.name' | 'userConfig.age'>;
47
- // type User = {
48
- // userConfig?: {
49
- // name?: string;
50
- // age?: number;
51
- // };
52
- // };
44
+ //=> {userConfig?: {name?: string; age?: number}}
53
45
 
54
46
  // Supports array
55
47
  type AddressConfig = PickDeep<Configuration, 'userConfig.address.0'>;
56
- // type AddressConfig = {
48
+ //=> {
57
49
  // userConfig: {
58
50
  // address: [{
59
51
  // city1: string;
@@ -64,14 +56,7 @@ type AddressConfig = PickDeep<Configuration, 'userConfig.address.0'>;
64
56
 
65
57
  // Supports recurse into array
66
58
  type Street = PickDeep<Configuration, 'userConfig.address.1.street2'>;
67
- // type Street = {
68
- // userConfig: {
69
- // address: [
70
- // unknown,
71
- // {street2: string}
72
- // ];
73
- // };
74
- // }
59
+ //=> {userConfig: {address: [unknown, {street2: string}]}}
75
60
  ```
76
61
 
77
62
  @category Object
@@ -86,7 +71,7 @@ export type PickDeep<T, PathUnion extends Paths<T>> =
86
71
  }[PathUnion]
87
72
  >
88
73
  : T extends object
89
- ? Simplify<UnionToIntersection<{
74
+ ? SimplifyDeep<UnionToIntersection<{
90
75
  [P in PathUnion]: InternalPickDeep<T, P>;
91
76
  }[PathUnion]>>
92
77
  : never;
@@ -15,19 +15,12 @@ type Foo = {
15
15
  c?: boolean | null;
16
16
  };
17
17
 
18
+ // Note: In the following example, `c` can no longer be `null`, but it's still optional.
18
19
  type SomeNonNullable = SetNonNullable<Foo, 'b' | 'c'>;
19
- // type SomeNonNullable = {
20
- // a: number | null;
21
- // b: string; // Can no longer be undefined.
22
- // c?: boolean; // Can no longer be null, but is still optional.
23
- // }
20
+ //=> {a: null | number; b: string; c?: boolean}
24
21
 
25
22
  type AllNonNullable = SetNonNullable<Foo>;
26
- // type AllNonNullable = {
27
- // a: number; // Can no longer be null.
28
- // b: string; // Can no longer be undefined.
29
- // c?: boolean; // Can no longer be null, but is still optional.
30
- // }
23
+ //=> {a: number; b: string; c?: boolean}
31
24
  ```
32
25
 
33
26
  @category Object
@@ -18,11 +18,7 @@ type Foo = {
18
18
  };
19
19
 
20
20
  type SomeOptional = SetOptional<Foo, 'b' | 'c'>;
21
- // type SomeOptional = {
22
- // a: number;
23
- // b?: string; // Was already optional and still is.
24
- // c?: boolean; // Is now optional.
25
- // }
21
+ //=> {a: number; b?: string; c?: boolean}
26
22
  ```
27
23
 
28
24
  @category Object
@@ -38,14 +38,14 @@ type MergeObjectToArray<TArray extends UnknownArray, TObject, TArrayCopy extends
38
38
  : K extends keyof TObject ? TObject[K] : TArray[K]
39
39
  }
40
40
  : TObject extends object
41
- // If `TObject` is a object witch key is number like `{0: string, 1: number}`
41
+ // If `TObject` is an object with number keys like `{0: string, 1: number}`
42
42
  ? {
43
43
  [K in keyof TArray]:
44
44
  K extends `${infer NumberK extends number}`
45
45
  ? NumberK extends keyof TObject ? TObject[NumberK] : TArray[K]
46
46
  : number extends K
47
47
  // If array key `K` is `number`, means it's a rest parameter, we should set the rest parameter type to corresponding type in `TObject`.
48
- // example: `MergeObjectToParamterArray<[string, ...boolean[]], {1: number}>` => `[string, ...number[]]`
48
+ // example: `MergeObjectToArray<[string, ...boolean[]], {1: number}>` => `[string, ...number[]]`
49
49
  ? StaticPartOfArray<TArrayCopy>['length'] extends keyof TObject
50
50
  ? TObject[StaticPartOfArray<TArrayCopy>['length']]
51
51
  : TArray[K]
@@ -18,11 +18,7 @@ type Foo = {
18
18
  };
19
19
 
20
20
  type SomeReadonly = SetReadonly<Foo, 'b' | 'c'>;
21
- // type SomeReadonly = {
22
- // a: number;
23
- // readonly b: string; // Was already readonly and still is.
24
- // readonly c: boolean; // Is now readonly.
25
- // }
21
+ //=> {a: number; readonly b: string; readonly c: boolean}
26
22
  ```
27
23
 
28
24
  @category Object
@@ -21,11 +21,7 @@ type Foo = {
21
21
  };
22
22
 
23
23
  type SomeRequired = SetRequired<Foo, 'b' | 'c'>;
24
- // type SomeRequired = {
25
- // a?: number;
26
- // b: string; // Was already required and still is.
27
- // c: boolean; // Is now required.
28
- // }
24
+ //=> {a?: number; b: string; c: boolean}
29
25
 
30
26
  // Set specific indices in an array to be required.
31
27
  type ArrayExample = SetRequired<[number?, number?, number?], 0 | 1>;
@@ -89,7 +89,7 @@ function displayPetInfoWithSharedUnionFieldsDeep(petInfo: SharedUnionFieldsDeep<
89
89
  export type SharedUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions = {}> =
90
90
  ApplyDefaultOptions<SharedUnionFieldsDeepOptions, DefaultSharedUnionFieldsDeepOptions, Options> extends infer OptionsWithDefaults extends Required<SharedUnionFieldsDeepOptions>
91
91
  // `Union extends` will convert `Union`
92
- // to a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
92
+ // to a [distributive conditional type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
93
93
  // But this is not what we want, so we need to wrap `Union` with `[]` to prevent it.
94
94
  ? [Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
95
95
  ? Union
@@ -0,0 +1,113 @@
1
+ import type {CollapseRestElement} from './internal/array.d.ts';
2
+ import type {ApplyDefaultOptions} from './internal/object.d.ts';
3
+ import type {IfNotAnyOrNever, Not} from './internal/type.d.ts';
4
+ import type {IsAny} from './is-any.d.ts';
5
+ import type {IsNever} from './is-never.d.ts';
6
+ import type {Or} from './or.d.ts';
7
+ import type {UnknownArray} from './unknown-array.d.ts';
8
+
9
+ /**
10
+ @see {@link SomeExtend}
11
+ */
12
+ export type SomeExtendOptions = {
13
+ /**
14
+ Consider `never` elements to match the target type only if the target type itself is `never` (or `any`).
15
+
16
+ - When set to `true` (default), `never` is _not_ treated as a bottom type, instead, it is treated as a type that matches only itself (or `any`).
17
+ - When set to `false`, `never` is treated as a bottom type, and behaves as it normally would.
18
+
19
+ @default true
20
+
21
+ @example
22
+ ```
23
+ import type {SomeExtend} from 'type-fest';
24
+
25
+ type A = SomeExtend<[1, 2, never], string, {strictNever: true}>;
26
+ //=> false
27
+
28
+ type B = SomeExtend<[1, 2, never], string, {strictNever: false}>;
29
+ //=> true
30
+
31
+ type C = SomeExtend<[1, never], never, {strictNever: true}>;
32
+ //=> true
33
+
34
+ type D = SomeExtend<[1, never], never, {strictNever: false}>;
35
+ //=> true
36
+
37
+ type E = SomeExtend<[never], any, {strictNever: true}>;
38
+ //=> true
39
+
40
+ type F = SomeExtend<[never], any, {strictNever: false}>;
41
+ //=> true
42
+ ```
43
+ */
44
+ strictNever?: boolean;
45
+ };
46
+
47
+ type DefaultSomeExtendOptions = {
48
+ strictNever: true;
49
+ };
50
+
51
+ /**
52
+ Returns a boolean for whether some element in an array type extends another type.
53
+
54
+ @example
55
+ ```
56
+ import type {SomeExtend} from 'type-fest';
57
+
58
+ type A = SomeExtend<['1', '2', 3], number>;
59
+ //=> true
60
+
61
+ type B = SomeExtend<[1, 2, 3], string>;
62
+ //=> false
63
+
64
+ type C = SomeExtend<[string, number | string], number>;
65
+ //=> boolean
66
+
67
+ type D = SomeExtend<[true, boolean, true], false>;
68
+ //=> boolean
69
+ ```
70
+
71
+ 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.
72
+
73
+ ```
74
+ // @exactOptionalPropertyTypes: true
75
+ import type {SomeExtend} from 'type-fest';
76
+
77
+ type A = SomeExtend<[1?, 2?, '3'?], string>;
78
+ //=> true
79
+ ```
80
+
81
+ ```
82
+ // @exactOptionalPropertyTypes: false
83
+ import type {SomeExtend} from 'type-fest';
84
+
85
+ type A = SomeExtend<[1?, 2?, '3'?], string>;
86
+ //=> boolean
87
+
88
+ type B = SomeExtend<[1?, 2?, '3'?], string | undefined>;
89
+ //=> true
90
+ ```
91
+
92
+ @see {@link SomeExtendOptions}
93
+
94
+ @category Utilities
95
+ @category Array
96
+ */
97
+ export type SomeExtend<TArray extends UnknownArray, Type, Options extends SomeExtendOptions = {}> =
98
+ _SomeExtend<CollapseRestElement<TArray>, Type, ApplyDefaultOptions<SomeExtendOptions, DefaultSomeExtendOptions, Options>>;
99
+
100
+ type _SomeExtend<TArray extends UnknownArray, Type, Options extends Required<SomeExtendOptions>> = IfNotAnyOrNever<TArray,
101
+ TArray extends readonly [infer First, ...infer Rest]
102
+ ? IsNever<First> extends true
103
+ ? Or<Or<IsNever<Type>, IsAny<Type>>, Not<Options['strictNever']>> extends true
104
+ // If target `Type` is also `never`, or is `any`, or `strictNever` is disabled, return `true`.
105
+ ? true
106
+ : _SomeExtend<Rest, Type, Options>
107
+ : First extends Type
108
+ ? true
109
+ : _SomeExtend<Rest, Type, Options>
110
+ : false,
111
+ false, false>;
112
+
113
+ export {};
@@ -41,11 +41,7 @@ const bar = {c: false};
41
41
  const fooBar = {...foo, ...bar};
42
42
 
43
43
  type FooBar = Spread<Foo, Bar>;
44
- // type FooBar = {
45
- // a: number;
46
- // b?: string | number | undefined;
47
- // c: boolean;
48
- // }
44
+ //=> {a: number; b?: string | number; c: boolean}
49
45
 
50
46
  declare function baz(argument: FooBar): void;
51
47
 
@@ -121,7 +121,7 @@ const moneyByAccountType: Record<UnwrapTagged<AccountType>, number> = {
121
121
  // Without UnwrapTagged, the following expression would throw a type error.
122
122
  const money = moneyByAccountType.SAVINGS; // TS error: Property 'SAVINGS' does not exist
123
123
 
124
- // Attempting to pass an non-Tagged type to UnwrapTagged will raise a type error.
124
+ // Attempting to pass a non-Tagged type to UnwrapTagged will raise a type error.
125
125
  // @ts-expect-error
126
126
  type WontWork = UnwrapTagged<string>;
127
127
  ```
@@ -239,7 +239,7 @@ const moneyByAccountType: Record<UnwrapOpaque<AccountType>, number> = {
239
239
  // Without UnwrapOpaque, the following expression would throw a type error.
240
240
  const money = moneyByAccountType.SAVINGS; // TS error: Property 'SAVINGS' does not exist
241
241
 
242
- // Attempting to pass an non-Opaque type to UnwrapOpaque will raise a type error.
242
+ // Attempting to pass a non-Opaque type to UnwrapOpaque will raise a type error.
243
243
  // @ts-expect-error
244
244
  type WontWork = UnwrapOpaque<string>;
245
245