type-fest 4.34.0 → 4.35.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
@@ -104,6 +104,7 @@ export type {HasWritableKeys} from './source/has-writable-keys';
104
104
  export type {Spread} from './source/spread';
105
105
  export type {IsInteger} from './source/is-integer';
106
106
  export type {IsFloat} from './source/is-float';
107
+ export type {TupleToObject} from './source/tuple-to-object';
107
108
  export type {TupleToUnion} from './source/tuple-to-union';
108
109
  export type {UnionToTuple} from './source/union-to-tuple';
109
110
  export type {IntRange} from './source/int-range';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "4.34.0",
3
+ "version": "4.35.0",
4
4
  "description": "A collection of essential TypeScript types",
5
5
  "license": "(MIT OR CC0-1.0)",
6
6
  "repository": "sindresorhus/type-fest",
@@ -69,7 +69,19 @@
69
69
  "error",
70
70
  "prefer-top-level"
71
71
  ]
72
- }
72
+ },
73
+ "overrides": [
74
+ {
75
+ "files": "**/*.d.ts",
76
+ "rules": {
77
+ "no-restricted-imports": [
78
+ "error",
79
+ "tsd",
80
+ "expect-type"
81
+ ]
82
+ }
83
+ }
84
+ ]
73
85
  },
74
86
  "tsd": {
75
87
  "compilerOptions": {
package/readme.md CHANGED
@@ -292,6 +292,7 @@ type ShouldBeNever = IfAny<'not any', 'not never', 'never'>;
292
292
  - [`ReadonlyTuple`](source/readonly-tuple.d.ts) - Create a type that represents a read-only tuple of the given type and length.
293
293
  - [`TupleToUnion`](source/tuple-to-union.d.ts) - Convert a tuple/array into a union type of its elements.
294
294
  - [`UnionToTuple`](source/union-to-tuple.d.ts) - Convert a union type into an unordered tuple type of its elements.
295
+ - [`TupleToObject`](source/tuple-to-object.d.ts) - Transforms a tuple into an object, mapping each tuple index to its corresponding type as a key-value pair.
295
296
 
296
297
  ### Numeric
297
298
 
@@ -1,4 +1,3 @@
1
- import type {UnionToTuple} from 'expect-type';
2
1
  import type {ArraySplice} from './array-splice';
3
2
  import type {ExactKey, IsArrayReadonly, NonRecursiveType, SetArrayAccess, ToString} from './internal';
4
3
  import type {IsEqual} from './is-equal';
@@ -6,6 +5,7 @@ import type {IsNever} from './is-never';
6
5
  import type {LiteralUnion} from './literal-union';
7
6
  import type {Paths} from './paths';
8
7
  import type {SimplifyDeep} from './simplify-deep';
8
+ import type {UnionToTuple} from './union-to-tuple';
9
9
  import type {UnknownArray} from './unknown-array';
10
10
 
11
11
  /**
package/source/paths.d.ts CHANGED
@@ -91,12 +91,48 @@ export type PathsOptions = {
91
91
  ```
92
92
  */
93
93
  leavesOnly?: boolean;
94
+
95
+ /**
96
+ Only include paths at the specified depth. By default all paths up to {@link PathsOptions.maxRecursionDepth | `maxRecursionDepth`} are included.
97
+
98
+ Note: Depth starts at `0` for root properties.
99
+
100
+ @default number
101
+
102
+ @example
103
+ ```
104
+ type Post = {
105
+ id: number;
106
+ author: {
107
+ id: number;
108
+ name: {
109
+ first: string;
110
+ last: string;
111
+ };
112
+ };
113
+ };
114
+
115
+ type DepthZero = Paths<Post, {depth: 0}>;
116
+ //=> 'id' | 'author'
117
+
118
+ type DepthOne = Paths<Post, {depth: 1}>;
119
+ //=> 'author.id' | 'author.name'
120
+
121
+ type DepthTwo = Paths<Post, {depth: 2}>;
122
+ //=> 'author.name.first' | 'author.name.last'
123
+
124
+ type LeavesAtDepthOne = Paths<Post, {leavesOnly: true; depth: 1}>;
125
+ //=> 'author.id'
126
+ ```
127
+ */
128
+ depth?: number;
94
129
  };
95
130
 
96
131
  type DefaultPathsOptions = {
97
132
  maxRecursionDepth: 10;
98
133
  bracketNotation: false;
99
134
  leavesOnly: false;
135
+ depth: number;
100
136
  };
101
137
 
102
138
  /**
@@ -147,6 +183,8 @@ export type Paths<T, Options extends PathsOptions = {}> = _Paths<T, {
147
183
  bracketNotation: Options['bracketNotation'] extends boolean ? Options['bracketNotation'] : DefaultPathsOptions['bracketNotation'];
148
184
  // Set default leavesOnly to false
149
185
  leavesOnly: Options['leavesOnly'] extends boolean ? Options['leavesOnly'] : DefaultPathsOptions['leavesOnly'];
186
+ // Set default depth to number
187
+ depth: Options['depth'] extends number ? Options['depth'] : DefaultPathsOptions['depth'];
150
188
  }>;
151
189
 
152
190
  type _Paths<T, Options extends Required<PathsOptions>> =
@@ -186,17 +224,36 @@ type InternalPaths<T, Options extends Required<PathsOptions>> =
186
224
  ) extends infer TranformedKey extends string | number ?
187
225
  // 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
188
226
  // 2. If style is 'a.0.b', transform 'Key' to `${Key}` | Key
189
- | (Options['leavesOnly'] extends true
227
+ | ((Options['leavesOnly'] extends true
190
228
  ? MaxDepth extends 0
191
229
  ? TranformedKey
192
230
  : T[Key] extends EmptyObject | readonly [] | NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
193
231
  ? TranformedKey
194
232
  : never
195
- : TranformedKey)
233
+ : TranformedKey
234
+ ) extends infer _TransformedKey
235
+ // If `depth` is provided, the condition becomes truthy only when it reaches `0`.
236
+ // Otherwise, since `depth` defaults to `number`, the condition is always truthy, returning paths at all depths.
237
+ ? 0 extends Options['depth']
238
+ ? _TransformedKey
239
+ : never
240
+ : never)
196
241
  | (
197
242
  // Recursively generate paths for the current key
198
243
  GreaterThan<MaxDepth, 0> extends true // Limit the depth to prevent infinite recursion
199
- ? _Paths<T[Key], {bracketNotation: Options['bracketNotation']; maxRecursionDepth: Subtract<MaxDepth, 1>; leavesOnly: Options['leavesOnly']}> extends infer SubPath
244
+ ? _Paths<T[Key],
245
+ {
246
+ bracketNotation: Options['bracketNotation'];
247
+ maxRecursionDepth: Subtract<MaxDepth, 1>;
248
+ leavesOnly: Options['leavesOnly'];
249
+ depth: Options['depth'] extends infer Depth extends number // For distributing `Options['depth']`
250
+ ? Depth extends 0 // Don't subtract further if `Depth` has reached `0`
251
+ ? never
252
+ : ToString<Depth> extends `-${number}` // Don't subtract if `Depth` is -ve
253
+ ? never
254
+ : Subtract<Options['depth'], 1> // If `Subtract` supported -ve numbers, then `depth` could have simply been `Subtract<Options['depth'], 1>`
255
+ : never; // Should never happen
256
+ }> extends infer SubPath
200
257
  ? SubPath extends string | number
201
258
  ? (
202
259
  Options['bracketNotation'] extends true
@@ -0,0 +1,42 @@
1
+ import type {IsTuple} from './is-tuple';
2
+ import type {UnknownArray} from './unknown-array';
3
+ import type {IfAny} from './if-any';
4
+
5
+ /**
6
+ Transforms a tuple into an object, mapping each tuple index to its corresponding type as a key-value pair.
7
+
8
+ Note: Tuple labels are [lost in the transformation process](https://stackoverflow.com/a/70398429/11719314). For example, `TupleToObject<[x: number, y: number]>` produces `{0: number; 1: number}`, and not `{x: number; y: number}`.
9
+
10
+ @example
11
+ ```
12
+ type Example1 = TupleToObject<[number, string, boolean]>;
13
+ //=> { 0: number; 1: string; 2: boolean }
14
+
15
+ // Tuples with optional indices
16
+ type Example2 = TupleToObject<[number, string?, boolean?]>;
17
+ //=> { 0: number; 1?: string; 2?: boolean }
18
+
19
+ // Readonly tuples
20
+ type Example3 = TupleToObject<readonly [number, string?]>;
21
+ //=> { readonly 0: number; readonly 1?: string }
22
+
23
+ // Non-tuple arrays get transformed into index signatures
24
+ type Example4 = TupleToObject<string[]>;
25
+ //=> { [x: number]: string }
26
+
27
+ // Tuples with rest elements
28
+ type Example5 = TupleToObject<[number, string, ...boolean[]]>;
29
+ //=> { [x: number]: number | string | boolean; 0: number; 1: string }
30
+
31
+ // Tuple labels are not preserved
32
+ type Example6 = TupleToObject<[x: number, y: number]>;
33
+ //=> { 0: number; 1: number }
34
+ ```
35
+
36
+ @category Array
37
+ */
38
+ export type TupleToObject<TArray extends UnknownArray> = IfAny<TArray, any, {
39
+ [
40
+ Key in keyof TArray as Key & (`${number}` | (IsTuple<TArray> extends true ? never : number))
41
+ ]: TArray[Key];
42
+ }>;