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 +2 -0
- package/package.json +1 -1
- package/readme.md +4 -0
- package/source/internal/array.d.ts +34 -1
- package/source/internal/object.d.ts +42 -0
- package/source/is-equal.d.ts +2 -2
- package/source/is-tuple.d.ts +78 -0
- package/source/partial-deep.d.ts +38 -10
- package/source/set-field-type.d.ts +32 -12
- package/source/set-optional.d.ts +3 -1
- package/source/set-readonly.d.ts +3 -1
- package/source/set-required-deep.d.ts +46 -0
- package/source/set-required.d.ts +39 -8
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
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
|
+
};
|
package/source/is-equal.d.ts
CHANGED
|
@@ -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
|
+
>>;
|
package/source/partial-deep.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
36
|
-
|
|
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
|
+
)>;
|
package/source/set-optional.d.ts
CHANGED
|
@@ -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<
|
|
37
|
+
Partial<HomomorphicPick<BaseType, Keys & KeysOfUnion<BaseType>>>
|
|
36
38
|
>
|
|
37
39
|
: never;
|
package/source/set-readonly.d.ts
CHANGED
|
@@ -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<
|
|
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
|
+
}>;
|
package/source/set-required.d.ts
CHANGED
|
@@ -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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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<
|
|
39
|
-
|
|
40
|
-
|
|
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
|