type-fest 4.7.0 → 4.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "4.7.0",
3
+ "version": "4.8.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/source/basic.d.ts CHANGED
@@ -4,7 +4,7 @@ Matches a [`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe
4
4
  @category Class
5
5
  */
6
6
  export type Class<T, Arguments extends unknown[] = any[]> = {
7
- prototype: T;
7
+ prototype: Pick<T, keyof T>;
8
8
  new(...arguments_: Arguments): T;
9
9
  };
10
10
 
@@ -25,7 +25,7 @@ We cannot use a `type` here because TypeScript throws: 'abstract' modifier canno
25
25
  */
26
26
  // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
27
27
  export interface AbstractClass<T, Arguments extends unknown[] = any[]> extends AbstractConstructor<T, Arguments> {
28
- prototype: T;
28
+ prototype: Pick<T, keyof T>;
29
29
  }
30
30
 
31
31
  /**
@@ -1,4 +1,5 @@
1
1
  import type {DelimiterCase} from './delimiter-case';
2
+ import type {UnknownArray} from './unknown-array';
2
3
 
3
4
  /**
4
5
  Convert object properties to delimiter case recursively.
@@ -49,12 +50,34 @@ export type DelimiterCasedPropertiesDeep<
49
50
  Delimiter extends string,
50
51
  > = Value extends Function | Date | RegExp
51
52
  ? Value
52
- : Value extends Array<infer U>
53
- ? Array<DelimiterCasedPropertiesDeep<U, Delimiter>>
54
- : Value extends Set<infer U>
55
- ? Set<DelimiterCasedPropertiesDeep<U, Delimiter>> : {
56
- [K in keyof Value as DelimiterCase<
57
- K,
58
- Delimiter
59
- >]: DelimiterCasedPropertiesDeep<Value[K], Delimiter>;
60
- };
53
+ : Value extends string
54
+ ? DelimiterCase<Value, Delimiter>
55
+ : Value extends UnknownArray
56
+ ? DelimiterCasedPropertiesArrayDeep<Value, Delimiter>
57
+ : Value extends Set<infer U>
58
+ ? Set<DelimiterCasedPropertiesDeep<U, Delimiter>> : {
59
+ [K in keyof Value as DelimiterCase<
60
+ K,
61
+ Delimiter
62
+ >]: DelimiterCasedPropertiesDeep<Value[K], Delimiter>;
63
+ };
64
+
65
+ type DelimiterCasedPropertiesArrayDeep<Value extends UnknownArray, Delimiter extends string> =
66
+ Value extends []
67
+ ? []
68
+ // Tailing spread array
69
+ : Value extends [infer U, ...infer V]
70
+ ? [DelimiterCasedPropertiesDeep<U, Delimiter>, ...DelimiterCasedPropertiesDeep<V, Delimiter>]
71
+ : Value extends readonly [infer U, ...infer V]
72
+ ? readonly [DelimiterCasedPropertiesDeep<U, Delimiter>, ...DelimiterCasedPropertiesDeep<V, Delimiter>]
73
+ // Leading spread array
74
+ : Value extends readonly [...infer U, infer V]
75
+ ? [...DelimiterCasedPropertiesDeep<U, Delimiter>, DelimiterCasedPropertiesDeep<V, Delimiter>]
76
+ : Value extends readonly [...infer U, infer V]
77
+ ? readonly [...DelimiterCasedPropertiesDeep<U, Delimiter>, DelimiterCasedPropertiesDeep<V, Delimiter>]
78
+ // Array
79
+ : Value extends Array<infer U>
80
+ ? Array<DelimiterCasedPropertiesDeep<U, Delimiter>>
81
+ : Value extends ReadonlyArray<infer U>
82
+ ? ReadonlyArray<DelimiterCasedPropertiesDeep<U, Delimiter>>
83
+ : never;
@@ -40,7 +40,7 @@ type B = BuildObject<'a', string, {readonly a?: any}>;
40
40
  //=> {readonly a?: string}
41
41
  ```
42
42
  */
43
- export type BuildObject<Key extends PropertyKey, Value, CopiedFrom extends UnknownRecord = {}> =
43
+ export type BuildObject<Key extends PropertyKey, Value, CopiedFrom extends object = {}> =
44
44
  Key extends keyof CopiedFrom
45
45
  ? Pick<{[_ in keyof CopiedFrom]: Value}, Key>
46
46
  : Key extends `${infer NumberKey extends number}`
@@ -67,9 +67,14 @@ export type Subtract<A extends number, B extends number> = BuildTuple<A> extends
67
67
  : never;
68
68
 
69
69
  /**
70
- Matches any primitive, `Date`, or `RegExp` value.
70
+ Matches any primitive, `Date`, `RegExp`, `Element` value.
71
71
  */
72
- export type BuiltIns = Primitive | Date | RegExp;
72
+ export type BuiltIns = Primitive | Date | RegExp | Element;
73
+
74
+ /**
75
+ Matches non-recursive types.
76
+ */
77
+ export type NonRecursiveType = BuiltIns | Function | (new (...args: any[]) => unknown);
73
78
 
74
79
  export type UpperCaseCharacters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
75
80
 
@@ -150,7 +155,16 @@ Extract the object field type if T is an object and K is a key of T, return `nev
150
155
 
151
156
  It creates a type-safe way to access the member type of `unknown` type.
152
157
  */
153
- export type ObjectValue<T, K> = K extends keyof T ? T[K] : never;
158
+ export type ObjectValue<T, K> =
159
+ K extends keyof T
160
+ ? T[K]
161
+ : ToString<K> extends keyof T
162
+ ? T[ToString<K>]
163
+ : K extends `${infer NumberK extends number}`
164
+ ? NumberK extends keyof T
165
+ ? T[NumberK]
166
+ : never
167
+ : never;
154
168
 
155
169
  /**
156
170
  Returns a boolean for whether the string is lowercased.
@@ -1,4 +1,4 @@
1
- import type {JsonPrimitive, JsonValue} from './basic';
1
+ import type {JsonPrimitive} from './basic';
2
2
 
3
3
  type JsonifiableObject = {[Key in string]?: Jsonifiable} | {toJSON: () => Jsonifiable};
4
4
  type JsonifiableArray = readonly Jsonifiable[];
@@ -1,4 +1,4 @@
1
- import type {BuiltIns, UnknownRecord} from './internal';
1
+ import type {BuiltIns} from './internal';
2
2
 
3
3
  /**
4
4
  @see PartialDeep
@@ -69,9 +69,8 @@ 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 UnknownRecord
73
- ? PartialObjectDeep<T, Options>
74
- : T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
72
+ : T extends object
73
+ ? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
75
74
  ? Options['recurseIntoArrays'] extends true
76
75
  ? ItemType[] extends T // Test for arrays (non-tuples) specifically
77
76
  ? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
@@ -79,7 +78,8 @@ export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends
79
78
  : Array<PartialDeep<ItemType | undefined, Options>>
80
79
  : PartialObjectDeep<T, Options> // Tuples behave properly
81
80
  : T // If they don't opt into array testing, just use the original type
82
- : T;
81
+ : PartialObjectDeep<T, Options>
82
+ : unknown;
83
83
 
84
84
  /**
85
85
  Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`.
@@ -1,4 +1,4 @@
1
- import type {CamelCase} from './camel-case';
1
+ import type {CamelCase, CamelCaseOptions} from './camel-case';
2
2
 
3
3
  /**
4
4
  Converts a string literal to pascal-case.
@@ -33,6 +33,6 @@ const dbResult: CamelCasedProperties<ModelProps> = {
33
33
  @category Change case
34
34
  @category Template literal
35
35
  */
36
- export type PascalCase<Value> = CamelCase<Value> extends string
37
- ? Capitalize<CamelCase<Value>>
38
- : CamelCase<Value>;
36
+ export type PascalCase<Value, Options extends CamelCaseOptions = {preserveConsecutiveUppercase: true}> = CamelCase<Value, Options> extends string
37
+ ? Capitalize<CamelCase<Value, Options>>
38
+ : CamelCase<Value, Options>;
@@ -1,3 +1,4 @@
1
+ import type {CamelCaseOptions} from './camel-case';
1
2
  import type {PascalCase} from './pascal-case';
2
3
 
3
4
  /**
@@ -44,11 +45,11 @@ const result: PascalCasedPropertiesDeep<UserWithFriends> = {
44
45
  @category Template literal
45
46
  @category Object
46
47
  */
47
- export type PascalCasedPropertiesDeep<Value> = Value extends Function | Date | RegExp
48
+ export type PascalCasedPropertiesDeep<Value, Options extends CamelCaseOptions = {preserveConsecutiveUppercase: true}> = Value extends Function | Date | RegExp
48
49
  ? Value
49
50
  : Value extends Array<infer U>
50
- ? Array<PascalCasedPropertiesDeep<U>>
51
+ ? Array<PascalCasedPropertiesDeep<U, Options>>
51
52
  : Value extends Set<infer U>
52
- ? Set<PascalCasedPropertiesDeep<U>> : {
53
- [K in keyof Value as PascalCase<K>]: PascalCasedPropertiesDeep<Value[K]>;
53
+ ? Set<PascalCasedPropertiesDeep<U, Options>> : {
54
+ [K in keyof Value as PascalCase<K, Options>]: PascalCasedPropertiesDeep<Value[K], Options>;
54
55
  };
@@ -1,3 +1,4 @@
1
+ import type {CamelCaseOptions} from './camel-case';
1
2
  import type {PascalCase} from './pascal-case';
2
3
 
3
4
  /**
@@ -27,8 +28,8 @@ const result: PascalCasedProperties<User> = {
27
28
  @category Template literal
28
29
  @category Object
29
30
  */
30
- export type PascalCasedProperties<Value> = Value extends Function
31
+ export type PascalCasedProperties<Value, Options extends CamelCaseOptions = {preserveConsecutiveUppercase: true}> = Value extends Function
31
32
  ? Value
32
33
  : Value extends Array<infer U>
33
34
  ? Value
34
- : {[K in keyof Value as PascalCase<K>]: Value[K]};
35
+ : {[K in keyof Value as PascalCase<K, Options>]: Value[K]};
package/source/paths.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import type {ToString} from './internal';
1
+ import type {NonRecursiveType, ToString} from './internal';
2
2
  import type {EmptyObject} from './empty-object';
3
3
  import type {IsAny} from './is-any';
4
4
  import type {IsNever} from './is-never';
5
5
  import type {UnknownArray} from './unknown-array';
6
- import type {UnknownRecord} from './unknown-record';
7
6
 
8
7
  /**
9
8
  Return the part of the given array with a fixed index.
@@ -78,30 +77,35 @@ open('listB.1'); // TypeError. Because listB only has one element.
78
77
  @category Object
79
78
  @category Array
80
79
  */
81
- export type Paths<T extends UnknownRecord | UnknownArray> =
82
- IsAny<T> extends true
80
+ export type Paths<T> =
81
+ T extends NonRecursiveType
83
82
  ? never
84
- : T extends UnknownArray
85
- ? number extends T['length']
86
- // We need to handle the fixed and non-fixed index part of the array separately.
87
- ? InternalPaths<FilterFixedIndexArray<T>>
88
- | InternalPaths<Array<FilterNotFixedIndexArray<T>[number]>>
89
- : InternalPaths<T>
90
- : InternalPaths<T>;
83
+ : IsAny<T> extends true
84
+ ? never
85
+ : T extends UnknownArray
86
+ ? number extends T['length']
87
+ // We need to handle the fixed and non-fixed index part of the array separately.
88
+ ? InternalPaths<FilterFixedIndexArray<T>>
89
+ | InternalPaths<Array<FilterNotFixedIndexArray<T>[number]>>
90
+ : InternalPaths<T>
91
+ : T extends object
92
+ ? InternalPaths<T>
93
+ : never;
91
94
 
92
- export type InternalPaths<_T extends UnknownRecord | UnknownArray, T = Required<_T>> =
95
+ export type InternalPaths<_T, T = Required<_T>> =
93
96
  T extends EmptyObject | readonly []
94
97
  ? never
95
98
  : {
96
99
  [Key in keyof T]:
97
100
  Key extends string | number // Limit `Key` to string or number.
98
- ? T[Key] extends UnknownRecord | UnknownArray
99
- ? (
100
- IsNever<Paths<T[Key]>> extends false
101
- // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
102
- ? Key | ToString<Key> | `${Key}.${Paths<T[Key]>}`
103
- : Key | ToString<Key>
104
- )
105
- : Key | ToString<Key>
101
+ // If `Key` is a number, return `Key | `${Key}``, because both `array[0]` and `array['0']` work.
102
+ ?
103
+ | Key
104
+ | ToString<Key>
105
+ | (
106
+ IsNever<Paths<T[Key]>> extends false
107
+ ? `${Key}.${Paths<T[Key]>}`
108
+ : never
109
+ )
106
110
  : never
107
111
  }[keyof T & (T extends UnknownArray ? number : unknown)];
@@ -1,9 +1,9 @@
1
- import type {BuildObject, BuildTuple, ToString} from './internal';
1
+ import type {BuildObject, BuildTuple, NonRecursiveType, ObjectValue} from './internal';
2
+ import type {IsNever} from './is-never';
2
3
  import type {Paths} from './paths';
3
4
  import type {Simplify} from './simplify.d';
4
5
  import type {UnionToIntersection} from './union-to-intersection.d';
5
6
  import type {UnknownArray} from './unknown-array';
6
- import type {UnknownRecord} from './unknown-record.d';
7
7
 
8
8
  /**
9
9
  Pick properties from a deeply-nested object.
@@ -37,7 +37,8 @@ type Configuration = {
37
37
  type NameConfig = PickDeep<Configuration, 'userConfig.name'>;
38
38
  // type NameConfig = {
39
39
  // userConfig: {
40
- // name: string;
40
+ // name: string;
41
+ // }
41
42
  // };
42
43
 
43
44
  // Supports optional properties
@@ -50,7 +51,7 @@ type User = PickDeep<PartialDeep<Configuration>, 'userConfig.name' | 'userConfig
50
51
  // };
51
52
 
52
53
  // Supports array
53
- type AddressConfig = PickDeep<Configuration, `userConfig.address.0`>;
54
+ type AddressConfig = PickDeep<Configuration, 'userConfig.address.0'>;
54
55
  // type AddressConfig = {
55
56
  // userConfig: {
56
57
  // address: [{
@@ -61,8 +62,8 @@ type AddressConfig = PickDeep<Configuration, `userConfig.address.0`>;
61
62
  // }
62
63
 
63
64
  // Supports recurse into array
64
- type Street = PickDeep<Configuration, `userConfig.address.1.street2`>;
65
- // type AddressConfig = {
65
+ type Street = PickDeep<Configuration, 'userConfig.address.1.street2'>;
66
+ // type Street = {
66
67
  // userConfig: {
67
68
  // address: [
68
69
  // unknown,
@@ -75,37 +76,44 @@ type Street = PickDeep<Configuration, `userConfig.address.1.street2`>;
75
76
  @category Object
76
77
  @category Array
77
78
  */
78
- export type PickDeep<T extends UnknownRecord | UnknownArray, PathUnion extends Paths<T>> =
79
- T extends UnknownRecord
80
- ? Simplify<UnionToIntersection<{
81
- [P in PathUnion]: InternalPickDeep<T, P>;
82
- }[PathUnion]>>
79
+ export type PickDeep<T, PathUnion extends Paths<T>> =
80
+ T extends NonRecursiveType
81
+ ? never
83
82
  : T extends UnknownArray
84
83
  ? UnionToIntersection<{
85
84
  [P in PathUnion]: InternalPickDeep<T, P>;
86
85
  }[PathUnion]
87
86
  >
88
- : never;
87
+ : T extends object
88
+ ? Simplify<UnionToIntersection<{
89
+ [P in PathUnion]: InternalPickDeep<T, P>;
90
+ }[PathUnion]>>
91
+ : never;
89
92
 
90
93
  /**
91
94
  Pick an object/array from the given object/array by one path.
92
95
  */
93
- type InternalPickDeep<
94
- T extends UnknownRecord | UnknownArray,
95
- Path extends string | number, // Checked paths, extracted from unchecked paths
96
- > =
97
- T extends UnknownArray ? PickDeepArray<T, Path>
98
- : T extends UnknownRecord ? Simplify<PickDeepObject<T, Path>>
99
- : never;
96
+ type InternalPickDeep<T, Path extends string | number> =
97
+ T extends NonRecursiveType
98
+ ? never
99
+ : T extends UnknownArray ? PickDeepArray<T, Path>
100
+ : T extends object ? Simplify<PickDeepObject<T, Path>>
101
+ : never;
100
102
 
101
103
  /**
102
104
  Pick an object from the given object by one path.
103
105
  */
104
- type PickDeepObject<RecordType extends UnknownRecord, P extends string | number> =
106
+ type PickDeepObject<RecordType extends object, P extends string | number> =
105
107
  P extends `${infer RecordKeyInPath}.${infer SubPath}`
106
- ? BuildObject<RecordKeyInPath, InternalPickDeep<NonNullable<RecordType[RecordKeyInPath]>, SubPath>, RecordType>
107
- : P extends keyof RecordType | ToString<keyof RecordType> // Handle number keys
108
- ? BuildObject<P, RecordType[P], RecordType>
108
+ ? ObjectValue<RecordType, RecordKeyInPath> extends infer ObjectV
109
+ ? IsNever<ObjectV> extends false
110
+ ? BuildObject<RecordKeyInPath, InternalPickDeep<NonNullable<ObjectV>, SubPath>, RecordType>
111
+ : never
112
+ : never
113
+ : ObjectValue<RecordType, P> extends infer ObjectV
114
+ ? IsNever<ObjectV> extends false
115
+ ? BuildObject<P, ObjectV, RecordType>
116
+ : never
109
117
  : never;
110
118
 
111
119
  /**