type-fest 4.33.0 → 4.34.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 +1 -0
- package/package.json +1 -1
- package/readme.md +1 -0
- package/source/all-union-fields.d.ts +88 -0
- package/source/internal/object.d.ts +37 -0
- package/source/omit-deep.d.ts +12 -4
- package/source/paths.d.ts +52 -2
- package/source/shared-union-fields.d.ts +1 -0
package/index.d.ts
CHANGED
|
@@ -130,6 +130,7 @@ export type {ArraySplice} from './source/array-splice';
|
|
|
130
130
|
export type {ArrayTail} from './source/array-tail';
|
|
131
131
|
export type {SetFieldType} from './source/set-field-type';
|
|
132
132
|
export type {Paths} from './source/paths';
|
|
133
|
+
export type {AllUnionFields} from './source/all-union-fields';
|
|
133
134
|
export type {SharedUnionFields} from './source/shared-union-fields';
|
|
134
135
|
export type {SharedUnionFieldsDeep} from './source/shared-union-fields-deep';
|
|
135
136
|
export type {IsNull} from './source/is-null';
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -203,6 +203,7 @@ Click the type names for complete docs.
|
|
|
203
203
|
- [`Paths`](source/paths.d.ts) - Generate a union of all possible paths to properties in the given object.
|
|
204
204
|
- [`SharedUnionFields`](source/shared-union-fields.d.ts) - Create a type with shared fields from a union of object types.
|
|
205
205
|
- [`SharedUnionFieldsDeep`](source/shared-union-fields-deep.d.ts) - Create a type with shared fields from a union of object types, deeply traversing nested structures.
|
|
206
|
+
- [`AllUnionFields`](source/all-union-fields.d.ts) - Create a type with all fields from a union of object types.
|
|
206
207
|
- [`DistributedOmit`](source/distributed-omit.d.ts) - Omits keys from a type, distributing the operation over a union.
|
|
207
208
|
- [`DistributedPick`](source/distributed-pick.d.ts) - Picks keys from a type, distributing the operation over a union.
|
|
208
209
|
- [`And`](source/and.d.ts) - Returns a boolean for whether two given types are both true.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type {NonRecursiveType, ReadonlyKeysOfUnion, ValueOfUnion} from './internal';
|
|
2
|
+
import type {KeysOfUnion} from './keys-of-union';
|
|
3
|
+
import type {SharedUnionFields} from './shared-union-fields';
|
|
4
|
+
import type {Simplify} from './simplify';
|
|
5
|
+
import type {UnknownArray} from './unknown-array';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
Create a type with all fields from a union of object types.
|
|
9
|
+
|
|
10
|
+
Use-cases:
|
|
11
|
+
- You want a safe object type where each key exists in the union object.
|
|
12
|
+
|
|
13
|
+
@example
|
|
14
|
+
```
|
|
15
|
+
import type {AllUnionFields} from 'type-fest';
|
|
16
|
+
|
|
17
|
+
type Cat = {
|
|
18
|
+
name: string;
|
|
19
|
+
type: 'cat';
|
|
20
|
+
catType: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type Dog = {
|
|
24
|
+
name: string;
|
|
25
|
+
type: 'dog';
|
|
26
|
+
dogType: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function displayPetInfo(petInfo: Cat | Dog) {
|
|
30
|
+
// typeof petInfo =>
|
|
31
|
+
// {
|
|
32
|
+
// name: string;
|
|
33
|
+
// type: 'cat';
|
|
34
|
+
// catType: string;
|
|
35
|
+
// } | {
|
|
36
|
+
// name: string;
|
|
37
|
+
// type: 'dog';
|
|
38
|
+
// dogType: string;
|
|
39
|
+
// }
|
|
40
|
+
|
|
41
|
+
console.log('name: ', petInfo.name);
|
|
42
|
+
console.log('type: ', petInfo.type);
|
|
43
|
+
|
|
44
|
+
// TypeScript complains about `catType` and `dogType` not existing on type `Cat | Dog`.
|
|
45
|
+
console.log('animal type: ', petInfo.catType ?? petInfo.dogType);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function displayPetInfo(petInfo: AllUnionFields<Cat | Dog>) {
|
|
49
|
+
// typeof petInfo =>
|
|
50
|
+
// {
|
|
51
|
+
// name: string;
|
|
52
|
+
// type: 'cat' | 'dog';
|
|
53
|
+
// catType?: string;
|
|
54
|
+
// dogType?: string;
|
|
55
|
+
// }
|
|
56
|
+
|
|
57
|
+
console.log('name: ', petInfo.name);
|
|
58
|
+
console.log('type: ', petInfo.type);
|
|
59
|
+
|
|
60
|
+
// No TypeScript error.
|
|
61
|
+
console.log('animal type: ', petInfo.catType ?? petInfo.dogType);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
@see SharedUnionFields
|
|
66
|
+
|
|
67
|
+
@category Object
|
|
68
|
+
@category Union
|
|
69
|
+
*/
|
|
70
|
+
export type AllUnionFields<Union> =
|
|
71
|
+
Extract<Union, NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> | UnknownArray> extends infer SkippedMembers
|
|
72
|
+
? Exclude<Union, SkippedMembers> extends infer RelevantMembers
|
|
73
|
+
?
|
|
74
|
+
| SkippedMembers
|
|
75
|
+
| Simplify<
|
|
76
|
+
// Include fields that are common in all union members
|
|
77
|
+
SharedUnionFields<RelevantMembers> &
|
|
78
|
+
// Include readonly fields present in any union member
|
|
79
|
+
{
|
|
80
|
+
readonly [P in ReadonlyKeysOfUnion<RelevantMembers>]?: ValueOfUnion<RelevantMembers, P & KeysOfUnion<RelevantMembers>>
|
|
81
|
+
} &
|
|
82
|
+
// Include remaining fields that are neither common nor readonly
|
|
83
|
+
{
|
|
84
|
+
[P in Exclude<KeysOfUnion<RelevantMembers>, ReadonlyKeysOfUnion<RelevantMembers> | keyof RelevantMembers>]?: ValueOfUnion<RelevantMembers, P>
|
|
85
|
+
}
|
|
86
|
+
>
|
|
87
|
+
: never
|
|
88
|
+
: never;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {Simplify} from '../simplify';
|
|
2
2
|
import type {UnknownArray} from '../unknown-array';
|
|
3
|
+
import type {IsEqual} from '../is-equal';
|
|
3
4
|
import type {KeysOfUnion} from '../keys-of-union';
|
|
4
5
|
import type {FilterDefinedKeys, FilterOptionalKeys} from './keys';
|
|
5
6
|
import type {NonRecursiveType} from './type';
|
|
@@ -122,3 +123,39 @@ type IndexSignature = HomomorphicPick<{[k: string]: unknown}, number>;
|
|
|
122
123
|
export type HomomorphicPick<T, Keys extends KeysOfUnion<T>> = {
|
|
123
124
|
[P in keyof T as Extract<P, Keys>]: T[P]
|
|
124
125
|
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
Extract all possible values for a given key from a union of object types.
|
|
129
|
+
|
|
130
|
+
@example
|
|
131
|
+
```
|
|
132
|
+
type Statuses = ValueOfUnion<{ id: 1, status: "open" } | { id: 2, status: "closed" }, "status">;
|
|
133
|
+
//=> "open" | "closed"
|
|
134
|
+
```
|
|
135
|
+
*/
|
|
136
|
+
export type ValueOfUnion<Union, Key extends KeysOfUnion<Union>> =
|
|
137
|
+
Union extends unknown ? Key extends keyof Union ? Union[Key] : never : never;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
Extract all readonly keys from a union of object types.
|
|
141
|
+
|
|
142
|
+
@example
|
|
143
|
+
```
|
|
144
|
+
type User = {
|
|
145
|
+
readonly id: string;
|
|
146
|
+
name: string;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
type Post = {
|
|
150
|
+
readonly id: string;
|
|
151
|
+
readonly author: string;
|
|
152
|
+
body: string;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
type ReadonlyKeys = ReadonlyKeysOfUnion<User | Post>;
|
|
156
|
+
//=> "id" | "author"
|
|
157
|
+
```
|
|
158
|
+
*/
|
|
159
|
+
export type ReadonlyKeysOfUnion<Union> = Union extends unknown ? keyof {
|
|
160
|
+
[Key in keyof Union as IsEqual<{[K in Key]: Union[Key]}, {readonly [K in Key]: Union[Key]}> extends true ? Key : never]: never
|
|
161
|
+
} : never;
|
package/source/omit-deep.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import type {UnionToTuple} from 'expect-type';
|
|
1
2
|
import type {ArraySplice} from './array-splice';
|
|
2
3
|
import type {ExactKey, IsArrayReadonly, NonRecursiveType, SetArrayAccess, ToString} from './internal';
|
|
3
4
|
import type {IsEqual} from './is-equal';
|
|
4
5
|
import type {IsNever} from './is-never';
|
|
5
6
|
import type {LiteralUnion} from './literal-union';
|
|
6
7
|
import type {Paths} from './paths';
|
|
7
|
-
import type {SharedUnionFieldsDeep} from './shared-union-fields-deep';
|
|
8
8
|
import type {SimplifyDeep} from './simplify-deep';
|
|
9
9
|
import type {UnknownArray} from './unknown-array';
|
|
10
10
|
|
|
@@ -92,11 +92,19 @@ type AddressInfo = OmitDeep<Info1, 'address.1.foo'>;
|
|
|
92
92
|
*/
|
|
93
93
|
export type OmitDeep<T, PathUnion extends LiteralUnion<Paths<T>, string>> =
|
|
94
94
|
SimplifyDeep<
|
|
95
|
-
|
|
96
|
-
{[P in PathUnion]: OmitDeepWithOnePath<T, P>}[PathUnion]
|
|
97
|
-
>,
|
|
95
|
+
OmitDeepHelper<T, UnionToTuple<PathUnion>>,
|
|
98
96
|
UnknownArray>;
|
|
99
97
|
|
|
98
|
+
/**
|
|
99
|
+
Internal helper for {@link OmitDeep}.
|
|
100
|
+
|
|
101
|
+
Recursively transforms `T` by applying {@link OmitDeepWithOnePath} for each path in `PathTuple`.
|
|
102
|
+
*/
|
|
103
|
+
type OmitDeepHelper<T, PathTuple extends UnknownArray> =
|
|
104
|
+
PathTuple extends [infer Path, ...infer RestPaths]
|
|
105
|
+
? OmitDeepHelper<OmitDeepWithOnePath<T, Path & (string | number)>, RestPaths>
|
|
106
|
+
: T;
|
|
107
|
+
|
|
100
108
|
/**
|
|
101
109
|
Omit one path from the given object/array.
|
|
102
110
|
*/
|
package/source/paths.d.ts
CHANGED
|
@@ -50,11 +50,53 @@ export type PathsOptions = {
|
|
|
50
50
|
```
|
|
51
51
|
*/
|
|
52
52
|
bracketNotation?: boolean;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
Only include leaf paths in the output.
|
|
56
|
+
|
|
57
|
+
@default false
|
|
58
|
+
|
|
59
|
+
@example
|
|
60
|
+
```
|
|
61
|
+
type Post = {
|
|
62
|
+
id: number;
|
|
63
|
+
author: {
|
|
64
|
+
id: number;
|
|
65
|
+
name: {
|
|
66
|
+
first: string;
|
|
67
|
+
last: string;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type AllPaths = Paths<Post, {leavesOnly: false}>;
|
|
73
|
+
//=> 'id' | 'author' | 'author.id' | 'author.name' | 'author.name.first' | 'author.name.last'
|
|
74
|
+
|
|
75
|
+
type LeafPaths = Paths<Post, {leavesOnly: true}>;
|
|
76
|
+
//=> 'id' | 'author.id' | 'author.name.first' | 'author.name.last'
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
@example
|
|
80
|
+
```
|
|
81
|
+
type ArrayExample = {
|
|
82
|
+
array: Array<{foo: string}>;
|
|
83
|
+
tuple: [string, {bar: string}];
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
type AllPaths = Paths<ArrayExample, {leavesOnly: false}>;
|
|
87
|
+
//=> 'array' | `array.${number}` | `array.${number}.foo` | 'tuple' | 'tuple.0' | 'tuple.1' | 'tuple.1.bar'
|
|
88
|
+
|
|
89
|
+
type LeafPaths = Paths<ArrayExample, {leavesOnly: true}>;
|
|
90
|
+
//=> `array.${number}.foo` | 'tuple.0' | 'tuple.1.bar'
|
|
91
|
+
```
|
|
92
|
+
*/
|
|
93
|
+
leavesOnly?: boolean;
|
|
53
94
|
};
|
|
54
95
|
|
|
55
96
|
type DefaultPathsOptions = {
|
|
56
97
|
maxRecursionDepth: 10;
|
|
57
98
|
bracketNotation: false;
|
|
99
|
+
leavesOnly: false;
|
|
58
100
|
};
|
|
59
101
|
|
|
60
102
|
/**
|
|
@@ -103,6 +145,8 @@ export type Paths<T, Options extends PathsOptions = {}> = _Paths<T, {
|
|
|
103
145
|
maxRecursionDepth: Options['maxRecursionDepth'] extends number ? Options['maxRecursionDepth'] : DefaultPathsOptions['maxRecursionDepth'];
|
|
104
146
|
// Set default bracketNotation to false
|
|
105
147
|
bracketNotation: Options['bracketNotation'] extends boolean ? Options['bracketNotation'] : DefaultPathsOptions['bracketNotation'];
|
|
148
|
+
// Set default leavesOnly to false
|
|
149
|
+
leavesOnly: Options['leavesOnly'] extends boolean ? Options['leavesOnly'] : DefaultPathsOptions['leavesOnly'];
|
|
106
150
|
}>;
|
|
107
151
|
|
|
108
152
|
type _Paths<T, Options extends Required<PathsOptions>> =
|
|
@@ -142,11 +186,17 @@ type InternalPaths<T, Options extends Required<PathsOptions>> =
|
|
|
142
186
|
) extends infer TranformedKey extends string | number ?
|
|
143
187
|
// 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
|
|
144
188
|
// 2. If style is 'a.0.b', transform 'Key' to `${Key}` | Key
|
|
145
|
-
|
|
|
189
|
+
| (Options['leavesOnly'] extends true
|
|
190
|
+
? MaxDepth extends 0
|
|
191
|
+
? TranformedKey
|
|
192
|
+
: T[Key] extends EmptyObject | readonly [] | NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
|
|
193
|
+
? TranformedKey
|
|
194
|
+
: never
|
|
195
|
+
: TranformedKey)
|
|
146
196
|
| (
|
|
147
197
|
// Recursively generate paths for the current key
|
|
148
198
|
GreaterThan<MaxDepth, 0> extends true // Limit the depth to prevent infinite recursion
|
|
149
|
-
? _Paths<T[Key], {bracketNotation: Options['bracketNotation']; maxRecursionDepth: Subtract<MaxDepth, 1
|
|
199
|
+
? _Paths<T[Key], {bracketNotation: Options['bracketNotation']; maxRecursionDepth: Subtract<MaxDepth, 1>; leavesOnly: Options['leavesOnly']}> extends infer SubPath
|
|
150
200
|
? SubPath extends string | number
|
|
151
201
|
? (
|
|
152
202
|
Options['bracketNotation'] extends true
|