type-fest 4.4.0 → 4.6.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 +6 -0
- package/package.json +3 -2
- package/readme.md +15 -7
- package/source/array-indices.d.ts +23 -0
- package/source/array-values.d.ts +22 -0
- package/source/exact.d.ts +2 -1
- package/source/int-range.d.ts +52 -0
- package/source/internal.d.ts +5 -12
- package/source/jsonify.d.ts +18 -18
- package/source/keys-of-union.d.ts +40 -0
- package/source/last-array-element.d.ts +18 -8
- package/source/override-properties.d.ts +8 -1
- package/source/partial-deep.d.ts +12 -14
- package/source/readonly-deep.d.ts +23 -21
- package/source/set-parameter-type.d.ts +68 -0
- package/source/undefined-on-partial-deep.d.ts +81 -0
- package/source/writable-deep.d.ts +29 -9
package/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './source/basic';
|
|
|
5
5
|
export * from './source/observable-like';
|
|
6
6
|
|
|
7
7
|
// Utilities
|
|
8
|
+
export type {KeysOfUnion} from './source/keys-of-union';
|
|
8
9
|
export type {EmptyObject, IsEmptyObject} from './source/empty-object';
|
|
9
10
|
export type {NonEmptyObject} from './source/non-empty-object';
|
|
10
11
|
export type {UnknownRecord} from './source/unknown-record';
|
|
@@ -24,6 +25,7 @@ export type {PickIndexSignature} from './source/pick-index-signature';
|
|
|
24
25
|
export type {PartialDeep, PartialDeepOptions} from './source/partial-deep';
|
|
25
26
|
export type {RequiredDeep} from './source/required-deep';
|
|
26
27
|
export type {PartialOnUndefinedDeep, PartialOnUndefinedDeepOptions} from './source/partial-on-undefined-deep';
|
|
28
|
+
export type {UndefinedOnPartialDeep} from './source/undefined-on-partial-deep';
|
|
27
29
|
export type {ReadonlyDeep} from './source/readonly-deep';
|
|
28
30
|
export type {LiteralUnion} from './source/literal-union';
|
|
29
31
|
export type {Promisable} from './source/promisable';
|
|
@@ -48,6 +50,7 @@ export type {IterableElement} from './source/iterable-element';
|
|
|
48
50
|
export type {Entry} from './source/entry';
|
|
49
51
|
export type {Entries} from './source/entries';
|
|
50
52
|
export type {SetReturnType} from './source/set-return-type';
|
|
53
|
+
export type {SetParameterType} from './source/set-parameter-type';
|
|
51
54
|
export type {Asyncify} from './source/asyncify';
|
|
52
55
|
export type {Simplify} from './source/simplify';
|
|
53
56
|
export type {Jsonify} from './source/jsonify';
|
|
@@ -81,6 +84,7 @@ export type {WritableKeysOf} from './source/writable-keys-of';
|
|
|
81
84
|
export type {HasWritableKeys} from './source/has-writable-keys';
|
|
82
85
|
export type {Spread} from './source/spread';
|
|
83
86
|
export type {TupleToUnion} from './source/tuple-to-union';
|
|
87
|
+
export type {IntRange} from './source/int-range';
|
|
84
88
|
export type {IsEqual} from './source/is-equal';
|
|
85
89
|
export type {
|
|
86
90
|
IsLiteral,
|
|
@@ -95,6 +99,8 @@ export type {IsNever} from './source/is-never';
|
|
|
95
99
|
export type {IfNever} from './source/if-never';
|
|
96
100
|
export type {IsUnknown} from './source/is-unknown';
|
|
97
101
|
export type {IfUnknown} from './source/if-unknown';
|
|
102
|
+
export type {ArrayIndices} from './source/array-indices';
|
|
103
|
+
export type {ArrayValues} from './source/array-values';
|
|
98
104
|
|
|
99
105
|
// Template literal types
|
|
100
106
|
export type {CamelCase} from './source/camel-case';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "type-fest",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"description": "A collection of essential TypeScript types",
|
|
5
5
|
"license": "(MIT OR CC0-1.0)",
|
|
6
6
|
"repository": "sindresorhus/type-fest",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"node": ">=16"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"test": "xo && tsd && tsc && node script/test/source-files-extension.js"
|
|
18
|
+
"test": "xo && tsd && tsc && npm run test:undefined-on-partial-deep && node script/test/source-files-extension.js",
|
|
19
|
+
"test:undefined-on-partial-deep": "cd test-d/undefined-on-partial-deep && tsc --project tsconfig.json"
|
|
19
20
|
},
|
|
20
21
|
"files": [
|
|
21
22
|
"index.d.ts",
|
package/readme.md
CHANGED
|
@@ -129,6 +129,7 @@ Click the type names for complete docs.
|
|
|
129
129
|
- [`PickIndexSignature`](source/pick-index-signature.d.ts) - Pick only index signatures from the given object type, leaving out all explicitly defined properties.
|
|
130
130
|
- [`PartialDeep`](source/partial-deep.d.ts) - Create a deeply optional version of another type. Use [`Partial<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype) if you only need one level deep.
|
|
131
131
|
- [`PartialOnUndefinedDeep`](source/partial-on-undefined-deep.d.ts) - Create a deep version of another type where all keys accepting `undefined` type are set to optional.
|
|
132
|
+
- [`UndefinedOnPartialDeep`](source/undefined-on-partial-deep.d.ts) - Create a deep version of another type where all optional keys are set to also accept `undefined`.
|
|
132
133
|
- [`ReadonlyDeep`](source/readonly-deep.d.ts) - Create a deeply immutable version of an `object`/`Map`/`Set`/`Array` type. Use [`Readonly<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype) if you only need one level deep.
|
|
133
134
|
- [`LiteralUnion`](source/literal-union.d.ts) - Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729).
|
|
134
135
|
- [`Tagged`](source/opaque.d.ts) - Create a [tagged type](https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d) that can support [multiple tags](https://github.com/sindresorhus/type-fest/issues/665) if needed.
|
|
@@ -153,12 +154,14 @@ Click the type names for complete docs.
|
|
|
153
154
|
- [`Entry`](source/entry.d.ts) - Create a type that represents the type of an entry of a collection.
|
|
154
155
|
- [`Entries`](source/entries.d.ts) - Create a type that represents the type of the entries of a collection.
|
|
155
156
|
- [`SetReturnType`](source/set-return-type.d.ts) - Create a function type with a return type of your choice and the same parameters as the given function type.
|
|
157
|
+
- [`SetParameterType`](source/set-parameter-type.d.ts) - Create a function that replaces some parameters with the given parameters.
|
|
156
158
|
- [`Simplify`](source/simplify.d.ts) - Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
|
|
157
159
|
- [`Get`](source/get.d.ts) - Get a deeply-nested property from an object using a key path, like [Lodash's `.get()`](https://lodash.com/docs/latest#get) function.
|
|
158
160
|
- [`StringKeyOf`](source/string-key-of.d.ts) - Get keys of the given type as strings.
|
|
159
161
|
- [`Schema`](source/schema.d.ts) - Create a deep version of another object type where property values are recursively replaced into a given value type.
|
|
160
162
|
- [`Exact`](source/exact.d.ts) - Create a type that does not allow extra properties.
|
|
161
163
|
- [`OptionalKeysOf`](source/optional-keys-of.d.ts) - Extract all optional keys from the given type.
|
|
164
|
+
- [`KeysOfUnion`](source/keys-of-union.d.ts) - Create a union of all keys from a given type, even those exclusive to specific union members.
|
|
162
165
|
- [`HasOptionalKeys`](source/has-optional-keys.d.ts) - Create a `true`/`false` type depending on whether the given type has any optional fields.
|
|
163
166
|
- [`RequiredKeysOf`](source/required-keys-of.d.ts) - Extract all required keys from the given type.
|
|
164
167
|
- [`HasRequiredKeys`](source/has-required-keys.d.ts) - Create a `true`/`false` type depending on whether the given type has any required fields.
|
|
@@ -169,6 +172,9 @@ Click the type names for complete docs.
|
|
|
169
172
|
- [`Spread`](source/spread.d.ts) - Mimic the type inferred by TypeScript when merging two objects or two arrays/tuples using the spread syntax.
|
|
170
173
|
- [`IsEqual`](source/is-equal.d.ts) - Returns a boolean for whether the two given types are equal.
|
|
171
174
|
- [`TaggedUnion`](source/tagged-union.d.ts) - Create a union of types that share a common discriminant property.
|
|
175
|
+
- [`IntRange`](source/int-range.d.ts) - Generate a union of numbers.
|
|
176
|
+
- [`ArrayIndices`](source/array-indices.d.ts) - Provides valid indices for a constant array or tuple.
|
|
177
|
+
- [`ArrayValues`](source/array-values.d.ts) - Provides all values for a constant array or tuple.
|
|
172
178
|
|
|
173
179
|
### Type Guard
|
|
174
180
|
|
|
@@ -293,13 +299,14 @@ type ShouldBeNever = IfAny<'not any', 'not never', 'never'>;
|
|
|
293
299
|
|
|
294
300
|
*If you know one of our types by a different name, add it here for discovery.*
|
|
295
301
|
|
|
296
|
-
- `Prettify`- See [`Simplify`](
|
|
297
|
-
- `Expand`- See [`Simplify`](
|
|
298
|
-
- `PartialBy` - See [`SetOptional`](
|
|
299
|
-
- `RecordDeep`- See [`Schema`](
|
|
300
|
-
- `Mutable`- See [`Writable`](
|
|
301
|
-
- `RequireOnlyOne` - See [`RequireExactlyOne`](
|
|
302
|
-
- `AtMostOne` - See [`RequireOneOrNone`](
|
|
302
|
+
- `Prettify`- See [`Simplify`](source/simplify.d.ts)
|
|
303
|
+
- `Expand`- See [`Simplify`](source/simplify.d.ts)
|
|
304
|
+
- `PartialBy` - See [`SetOptional`](source/set-optional.d.ts)
|
|
305
|
+
- `RecordDeep`- See [`Schema`](source/schema.d.ts)
|
|
306
|
+
- `Mutable`- See [`Writable`](source/writable.d.ts)
|
|
307
|
+
- `RequireOnlyOne` - See [`RequireExactlyOne`](source/require-exactly-one.d.ts)
|
|
308
|
+
- `AtMostOne` - See [`RequireOneOrNone`](source/require-one-or-none.d.ts)
|
|
309
|
+
- `AllKeys` - See [`KeysOfUnion`](source/keys-of-union.d.ts)
|
|
303
310
|
|
|
304
311
|
## Tips
|
|
305
312
|
|
|
@@ -933,6 +940,7 @@ You can find some examples in the [TypeScript docs](https://www.typescriptlang.o
|
|
|
933
940
|
## Maintainers
|
|
934
941
|
|
|
935
942
|
- [Sindre Sorhus](https://github.com/sindresorhus)
|
|
943
|
+
- [Haozheng Li](https://github.com/Emiyaaaaa)
|
|
936
944
|
- [Jarek Radosz](https://github.com/CvX)
|
|
937
945
|
- [Dimitri Benin](https://github.com/BendingBender)
|
|
938
946
|
- [Pelle Wessman](https://github.com/voxpelli)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Provides valid indices for a constant array or tuple.
|
|
3
|
+
|
|
4
|
+
Use-case: This type is useful when working with constant arrays or tuples and you want to enforce type-safety for accessing elements by their indices.
|
|
5
|
+
|
|
6
|
+
@example
|
|
7
|
+
```
|
|
8
|
+
import type {ArrayIndices, ArrayValues} from 'type-fest';
|
|
9
|
+
|
|
10
|
+
const weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] as const;
|
|
11
|
+
|
|
12
|
+
type Weekday = ArrayIndices<typeof weekdays>;
|
|
13
|
+
type WeekdayName = ArrayValues<typeof weekdays>;
|
|
14
|
+
|
|
15
|
+
const getWeekdayName = (day: Weekday): WeekdayName => weekdays[day];
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
@see {@link ArrayValues}
|
|
19
|
+
|
|
20
|
+
@category Array
|
|
21
|
+
*/
|
|
22
|
+
export type ArrayIndices<Element extends readonly unknown[]> =
|
|
23
|
+
Exclude<Partial<Element>['length'], Element['length']>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Provides all values for a constant array or tuple.
|
|
3
|
+
|
|
4
|
+
Use-case: This type is useful when working with constant arrays or tuples and you want to enforce type-safety with their values.
|
|
5
|
+
|
|
6
|
+
@example
|
|
7
|
+
```
|
|
8
|
+
import type {ArrayValues, ArrayIndices} from 'type-fest';
|
|
9
|
+
|
|
10
|
+
const weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] as const;
|
|
11
|
+
|
|
12
|
+
type WeekdayName = ArrayValues<typeof weekdays>;
|
|
13
|
+
type Weekday = ArrayIndices<typeof weekdays>;
|
|
14
|
+
|
|
15
|
+
const getWeekdayName = (day: Weekday): WeekdayName => weekdays[day];
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
@see {@link ArrayIndices}
|
|
19
|
+
|
|
20
|
+
@category Array
|
|
21
|
+
*/
|
|
22
|
+
export type ArrayValues<T extends readonly unknown[]> = T[number];
|
package/source/exact.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {ArrayElement, ObjectValue} from './internal';
|
|
2
2
|
import type {Opaque, TagContainer} from './opaque';
|
|
3
3
|
import type {IsEqual} from './is-equal';
|
|
4
|
+
import type {KeysOfUnion} from './keys-of-union';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
Create a type from `ParameterType` and `InputType` and change keys exclusive to `InputType` to `never`.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type {BuildTuple, Subtract} from './internal';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Generate a union of numbers.
|
|
5
|
+
|
|
6
|
+
The numbers are created from the given `Start` (inclusive) parameter to the given `End` (exclusive) parameter.
|
|
7
|
+
|
|
8
|
+
You skip over numbers using the `Step` parameter (defaults to `1`). For example, `IntRange<0, 10, 2>` will create a union of `0 | 2 | 4 | 6 | 8`.
|
|
9
|
+
|
|
10
|
+
Note: `Start` or `End` must smaller than `1000`.
|
|
11
|
+
|
|
12
|
+
Use-cases:
|
|
13
|
+
1. This can be used to define a set of valid input/output values. for example:
|
|
14
|
+
```
|
|
15
|
+
type Age = IntRange<0, 120>;
|
|
16
|
+
type FontSize = IntRange<10, 20>;
|
|
17
|
+
type EvenNumber = IntRange<0, 11, 2>; //=> 0 | 2 | 4 | 6 | 8 | 10
|
|
18
|
+
```
|
|
19
|
+
2. This can be used to define random numbers in a range. For example, `type RandomNumber = IntRange<0, 100>;`
|
|
20
|
+
|
|
21
|
+
@example
|
|
22
|
+
```
|
|
23
|
+
import type {IntRange} from 'type-fest';
|
|
24
|
+
|
|
25
|
+
// Create union type `0 | 1 | ... | 9`
|
|
26
|
+
type ZeroToNine = IntRange<0, 10>;
|
|
27
|
+
|
|
28
|
+
// Create union type `100 | 200 | 300 | ... | 900`
|
|
29
|
+
type Hundreds = IntRange<100, 901, 100>;
|
|
30
|
+
```
|
|
31
|
+
*/
|
|
32
|
+
export type IntRange<Start extends number, End extends number, Step extends number = 1> = PrivateIntRange<Start, End, Step>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
The actual implementation of `IntRange`. It's private because it has some arguments that don't need to be exposed.
|
|
36
|
+
*/
|
|
37
|
+
type PrivateIntRange<
|
|
38
|
+
Start extends number,
|
|
39
|
+
End extends number,
|
|
40
|
+
Step extends number,
|
|
41
|
+
Gap extends number = Subtract<Step, 1>, // The gap between each number, gap = step - 1
|
|
42
|
+
List extends unknown[] = BuildTuple<Start, never>, // The final `List` is `[...StartLengthTuple, ...[number, ...GapLengthTuple], ...[number, ...GapLengthTuple], ... ...]`, so can initialize the `List` with `[...StartLengthTuple]`
|
|
43
|
+
EndLengthTuple extends unknown[] = BuildTuple<End>,
|
|
44
|
+
> = Gap extends 0 ?
|
|
45
|
+
// Handle the case that without `Step`
|
|
46
|
+
List['length'] extends End // The result of "List[length] === End"
|
|
47
|
+
? Exclude<List[number], never> // All unused elements are `never`, so exclude them
|
|
48
|
+
: PrivateIntRange<Start, End, Step, Gap, [...List, List['length'] ]>
|
|
49
|
+
// Handle the case that with `Step`
|
|
50
|
+
: List extends [...(infer U), ...EndLengthTuple] // The result of "List[length] >= End", because the `...BuildTuple<Gap, never>` maybe make `List` too long.
|
|
51
|
+
? Exclude<List[number], never>
|
|
52
|
+
: PrivateIntRange<Start, End, Step, Gap, [...List, List['length'], ...BuildTuple<Gap, never>]>;
|
package/source/internal.d.ts
CHANGED
|
@@ -14,13 +14,15 @@ Infer the length of the given array `<T>`.
|
|
|
14
14
|
type TupleLength<T extends readonly unknown[]> = T extends {readonly length: infer L} ? L : never;
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
Create a tuple type of the given length `<L>`.
|
|
17
|
+
Create a tuple type of the given length `<L>` and fill it with the given type `<Fill>`.
|
|
18
|
+
|
|
19
|
+
If `<Fill>` is not provided, it will default to `unknown`.
|
|
18
20
|
|
|
19
21
|
@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
|
|
20
22
|
*/
|
|
21
|
-
type BuildTuple<L extends number, T extends readonly unknown[] = []> = T extends {readonly length: L}
|
|
23
|
+
export type BuildTuple<L extends number, Fill = unknown, T extends readonly unknown[] = []> = T extends {readonly length: L}
|
|
22
24
|
? T
|
|
23
|
-
: BuildTuple<L, [...T,
|
|
25
|
+
: BuildTuple<L, Fill, [...T, Fill]>;
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
Create a tuple of length `A` and a tuple composed of two other tuples,
|
|
@@ -37,15 +39,6 @@ Matches any primitive, `Date`, or `RegExp` value.
|
|
|
37
39
|
*/
|
|
38
40
|
export type BuiltIns = Primitive | Date | RegExp;
|
|
39
41
|
|
|
40
|
-
/**
|
|
41
|
-
Gets keys from a type. Similar to `keyof` but this one also works for union types.
|
|
42
|
-
|
|
43
|
-
The reason a simple `keyof Union` does not work is because `keyof` always returns the accessible keys of a type. In the case of a union, that will only be the common keys.
|
|
44
|
-
|
|
45
|
-
@link https://stackoverflow.com/a/49402091
|
|
46
|
-
*/
|
|
47
|
-
export type KeysOfUnion<T> = T extends T ? keyof T : never;
|
|
48
|
-
|
|
49
42
|
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';
|
|
50
43
|
|
|
51
44
|
export type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
|
package/source/jsonify.d.ts
CHANGED
|
@@ -96,24 +96,24 @@ export type Jsonify<T> = IsAny<T> extends true
|
|
|
96
96
|
? null
|
|
97
97
|
: T extends JsonPrimitive
|
|
98
98
|
? T
|
|
99
|
-
: //
|
|
100
|
-
T extends
|
|
101
|
-
?
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
99
|
+
: // Any object with toJSON is special case
|
|
100
|
+
T extends {toJSON(): infer J}
|
|
101
|
+
? (() => J) extends () => JsonValue // Is J assignable to JsonValue?
|
|
102
|
+
? J // Then T is Jsonable and its Jsonable value is J
|
|
103
|
+
: Jsonify<J> // Maybe if we look a level deeper we'll find a JsonValue
|
|
104
|
+
: // Instanced primitives are objects
|
|
105
|
+
T extends Number
|
|
106
|
+
? number
|
|
107
|
+
: T extends String
|
|
108
|
+
? string
|
|
109
|
+
: T extends Boolean
|
|
110
|
+
? boolean
|
|
111
|
+
: T extends Map<any, any> | Set<any>
|
|
112
|
+
? EmptyObject
|
|
113
|
+
: T extends TypedArray
|
|
114
|
+
? Record<string, number>
|
|
115
|
+
: T extends NotJsonable
|
|
116
|
+
? never // Non-JSONable type union was found not empty
|
|
117
117
|
: T extends []
|
|
118
118
|
? []
|
|
119
119
|
: T extends unknown[]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Create a union of all keys from a given type, even those exclusive to specific union members.
|
|
3
|
+
|
|
4
|
+
Unlike the native `keyof` keyword, which returns keys present in **all** union members, this type returns keys from **any** member.
|
|
5
|
+
|
|
6
|
+
@link https://stackoverflow.com/a/49402091
|
|
7
|
+
|
|
8
|
+
@example
|
|
9
|
+
```
|
|
10
|
+
import type {KeysOfUnion} from 'type-fest';
|
|
11
|
+
|
|
12
|
+
type A = {
|
|
13
|
+
common: string;
|
|
14
|
+
a: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type B = {
|
|
18
|
+
common: string;
|
|
19
|
+
b: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type C = {
|
|
23
|
+
common: string;
|
|
24
|
+
c: boolean;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type Union = A | B | C;
|
|
28
|
+
|
|
29
|
+
type CommonKeys = keyof Union;
|
|
30
|
+
//=> 'common'
|
|
31
|
+
|
|
32
|
+
type AllKeys = KeysOfUnion<Union>;
|
|
33
|
+
//=> 'common' | 'a' | 'b' | 'c'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
@category Object
|
|
37
|
+
*/
|
|
38
|
+
export type KeysOfUnion<ObjectType> = ObjectType extends unknown
|
|
39
|
+
? keyof ObjectType
|
|
40
|
+
: never;
|
|
@@ -13,16 +13,26 @@ const array = ['foo', 2];
|
|
|
13
13
|
|
|
14
14
|
typeof lastOf(array);
|
|
15
15
|
//=> number
|
|
16
|
+
|
|
17
|
+
const array = ['foo', 2] as const;
|
|
18
|
+
|
|
19
|
+
typeof lastOf(array);
|
|
20
|
+
//=> 2
|
|
16
21
|
```
|
|
17
22
|
|
|
18
23
|
@category Array
|
|
19
24
|
@category Template literal
|
|
20
25
|
*/
|
|
21
|
-
export type LastArrayElement<Elements extends readonly unknown[]>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
export type LastArrayElement<Elements extends readonly unknown[], ElementBeforeTailingSpreadElement = never> =
|
|
27
|
+
// If the last element of an array is a spread element, the `LastArrayElement` result should be `'the type of the element before the spread element' | 'the type of the spread element'`.
|
|
28
|
+
Elements extends readonly []
|
|
29
|
+
? ElementBeforeTailingSpreadElement
|
|
30
|
+
: Elements extends readonly [...infer U, infer V]
|
|
31
|
+
? V
|
|
32
|
+
: Elements extends readonly [infer U, ...infer V]
|
|
33
|
+
// If we return `V[number] | U` directly, it would be wrong for `[[string, boolean, object, ...number[]]`.
|
|
34
|
+
// So we need to recurse type `V` and carry over the type of the element before the spread element.
|
|
35
|
+
? LastArrayElement<V, U>
|
|
36
|
+
: Elements extends ReadonlyArray<infer U>
|
|
37
|
+
? U | ElementBeforeTailingSpreadElement
|
|
38
|
+
: never;
|
|
@@ -25,5 +25,12 @@ type Fizz = OverrideProperties<Foo, {b: number; c: number}>
|
|
|
25
25
|
*/
|
|
26
26
|
export type OverrideProperties<
|
|
27
27
|
TOriginal,
|
|
28
|
-
|
|
28
|
+
// This first bit where we use `Partial` is to enable autocomplete
|
|
29
|
+
// and the second bit with the mapped type is what enforces that we don't try
|
|
30
|
+
// to override properties that doesn't exist in the original type.
|
|
31
|
+
TOverride extends Partial<Record<keyof TOriginal, unknown>> & {
|
|
32
|
+
[Key in keyof TOverride]: Key extends keyof TOriginal
|
|
33
|
+
? TOverride[Key]
|
|
34
|
+
: never;
|
|
35
|
+
},
|
|
29
36
|
> = Merge<TOriginal, TOverride>;
|
package/source/partial-deep.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
|
|
|
59
59
|
@category Set
|
|
60
60
|
@category Map
|
|
61
61
|
*/
|
|
62
|
-
export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIns
|
|
62
|
+
export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIns | (((...arguments_: any[]) => unknown)) | (new (...arguments_: any[]) => unknown)
|
|
63
63
|
? T
|
|
64
64
|
: T extends Map<infer KeyType, infer ValueType>
|
|
65
65
|
? PartialMapDeep<KeyType, ValueType, Options>
|
|
@@ -69,19 +69,17 @@ 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
|
|
73
|
-
? T
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
: PartialObjectDeep<T, Options>
|
|
84
|
-
: unknown;
|
|
72
|
+
: T extends object
|
|
73
|
+
? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
|
|
74
|
+
? Options['recurseIntoArrays'] extends true
|
|
75
|
+
? ItemType[] extends T // Test for arrays (non-tuples) specifically
|
|
76
|
+
? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
|
|
77
|
+
? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
|
|
78
|
+
: Array<PartialDeep<ItemType | undefined, Options>>
|
|
79
|
+
: PartialObjectDeep<T, Options> // Tuples behave properly
|
|
80
|
+
: T // If they don't opt into array testing, just use the original type
|
|
81
|
+
: PartialObjectDeep<T, Options>
|
|
82
|
+
: unknown;
|
|
85
83
|
|
|
86
84
|
/**
|
|
87
85
|
Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`.
|
|
@@ -38,28 +38,30 @@ Note that types containing overloaded functions are not made deeply readonly due
|
|
|
38
38
|
*/
|
|
39
39
|
export type ReadonlyDeep<T> = T extends BuiltIns
|
|
40
40
|
? T
|
|
41
|
-
: T extends (...
|
|
42
|
-
?
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
: T extends new (...args: any[]) => unknown
|
|
42
|
+
? T // Skip class constructors
|
|
43
|
+
: T extends (...arguments_: any[]) => unknown
|
|
44
|
+
? {} extends ReadonlyObjectDeep<T>
|
|
45
45
|
? T
|
|
46
|
-
:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
: T extends Readonly<
|
|
50
|
-
?
|
|
51
|
-
:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
? readonly [
|
|
56
|
-
: T extends readonly [
|
|
57
|
-
? readonly [
|
|
58
|
-
: T extends
|
|
59
|
-
?
|
|
60
|
-
: T extends
|
|
61
|
-
?
|
|
62
|
-
:
|
|
46
|
+
: HasMultipleCallSignatures<T> extends true
|
|
47
|
+
? T
|
|
48
|
+
: ((...arguments_: Parameters<T>) => ReturnType<T>) & ReadonlyObjectDeep<T>
|
|
49
|
+
: T extends Readonly<ReadonlyMap<infer KeyType, infer ValueType>>
|
|
50
|
+
? ReadonlyMapDeep<KeyType, ValueType>
|
|
51
|
+
: T extends Readonly<ReadonlySet<infer ItemType>>
|
|
52
|
+
? ReadonlySetDeep<ItemType>
|
|
53
|
+
: // Identify tuples to avoid converting them to arrays inadvertently; special case `readonly [...never[]]`, as it emerges undesirably from recursive invocations of ReadonlyDeep below.
|
|
54
|
+
T extends readonly [] | readonly [...never[]]
|
|
55
|
+
? readonly []
|
|
56
|
+
: T extends readonly [infer U, ...infer V]
|
|
57
|
+
? readonly [ReadonlyDeep<U>, ...ReadonlyDeep<V>]
|
|
58
|
+
: T extends readonly [...infer U, infer V]
|
|
59
|
+
? readonly [...ReadonlyDeep<U>, ReadonlyDeep<V>]
|
|
60
|
+
: T extends ReadonlyArray<infer ItemType>
|
|
61
|
+
? ReadonlyArray<ReadonlyDeep<ItemType>>
|
|
62
|
+
: T extends object
|
|
63
|
+
? ReadonlyObjectDeep<T>
|
|
64
|
+
: unknown;
|
|
63
65
|
|
|
64
66
|
/**
|
|
65
67
|
Same as `ReadonlyDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `ReadonlyDeep`.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type {IsUnknown} from './is-unknown';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Create a tuple that replaces the given `Tuple`'s elements with the given `Record_`'s values at the given indices.
|
|
5
|
+
*/
|
|
6
|
+
type MergeObjectToTuple<Tuple extends unknown[], Record_ extends Record<number, unknown>> = {
|
|
7
|
+
[K in keyof Tuple]: Record_ extends Record<string, unknown>
|
|
8
|
+
// Handle object case like `{0: string, 1: number}`
|
|
9
|
+
? K extends `${infer NumberK extends number}`
|
|
10
|
+
? NumberK extends keyof Record_ ? Record_[K] : Tuple[K]
|
|
11
|
+
: never // Should not happen
|
|
12
|
+
// Handle tuple case like `[string, number]`
|
|
13
|
+
: K extends keyof Record_ ? Record_[K] : Tuple[K]
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
Create a function that replaces some parameters with the given parameters.
|
|
18
|
+
|
|
19
|
+
The parameters that are not specified will be kept as-is.
|
|
20
|
+
|
|
21
|
+
Note:
|
|
22
|
+
- This type will ignore the given function's generic type.
|
|
23
|
+
- If you change the parameter type that return type depends on, the return type will not change:
|
|
24
|
+
```
|
|
25
|
+
const fn = (a: number) => a;
|
|
26
|
+
//=> fn: (a: number) => number;
|
|
27
|
+
|
|
28
|
+
// We change type of `a` to `string`, but return type is still `number`.
|
|
29
|
+
type Fn = SetParameterType<typeof fn, {0: string}>;
|
|
30
|
+
//=> (a: string) => number;
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Use-case:
|
|
34
|
+
- Define a wrapped function that receives something different while returning the same type.
|
|
35
|
+
- Mocking and testing.
|
|
36
|
+
- Overload function type. (See example)
|
|
37
|
+
|
|
38
|
+
@example
|
|
39
|
+
```
|
|
40
|
+
import type {SetParameterType} from 'type-fest';
|
|
41
|
+
|
|
42
|
+
type HandleMessage = (data: Data, message: string) => void;
|
|
43
|
+
|
|
44
|
+
type HandleOk = SetParameterType<HandleMessage, {0: SuccessData, 1: 'ok'}>;
|
|
45
|
+
//=> type HandleOk = (data: SuccessData, message: 'ok') => void;
|
|
46
|
+
|
|
47
|
+
// Another way to define the parameters to replace.
|
|
48
|
+
type HandleError = SetParameterType<HandleMessage, [data: ErrorData, message: 'error']>;
|
|
49
|
+
//=> type HandleError = (data: ErrorData, message: 'error') => void;
|
|
50
|
+
|
|
51
|
+
// Could change single parameter type.
|
|
52
|
+
type HandleWarn = SetParameterType<HandleMessage, {1: 'warn'}>;
|
|
53
|
+
//=> type HandleWarn = (data: Data, message: 'warn') => void;
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
@category Function
|
|
57
|
+
*/
|
|
58
|
+
export type SetParameterType<Fn extends (...arguments_: any[]) => unknown, P extends Record<number, unknown>> =
|
|
59
|
+
// Just using `Parameters<Fn>` isn't ideal because it doesn't handle the `this` fake parameter.
|
|
60
|
+
Fn extends (this: infer ThisArg, ...arguments_: infer Arguments) => unknown
|
|
61
|
+
? (
|
|
62
|
+
// If a function did not specify the `this` fake parameter, it will be inferred to `unknown`.
|
|
63
|
+
// We want to detect this situation just to display a friendlier type upon hovering on an IntelliSense-powered IDE.
|
|
64
|
+
IsUnknown<ThisArg> extends true
|
|
65
|
+
? (...arguments_: MergeObjectToTuple<Arguments, P>) => ReturnType<Fn>
|
|
66
|
+
: (this: ThisArg, ...arguments_: MergeObjectToTuple<Arguments, P>) => ReturnType<Fn>
|
|
67
|
+
)
|
|
68
|
+
: Fn; // This part should be unreachable
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type {BuiltIns} from './internal';
|
|
2
|
+
import type {Merge} from './merge';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
Create a deep version of another type where all optional keys are set to also accept `undefined`.
|
|
6
|
+
|
|
7
|
+
Note: This is only needed when the [`exactOptionalPropertyTypes`](https://www.typescriptlang.org/tsconfig#exactOptionalPropertyTypes) TSConfig setting is enabled.
|
|
8
|
+
|
|
9
|
+
Use-cases:
|
|
10
|
+
- When `exactOptionalPropertyTypes` is enabled, an object like `{a: undefined}` is not assignable to the type `{a?: number}`. You can use `UndefinedOnPartialDeep<{a?: number}>` to make it assignable.
|
|
11
|
+
|
|
12
|
+
@example
|
|
13
|
+
```
|
|
14
|
+
import type {UndefinedOnPartialDeep} from 'type-fest';
|
|
15
|
+
|
|
16
|
+
interface Settings {
|
|
17
|
+
optionA: string;
|
|
18
|
+
optionB?: number;
|
|
19
|
+
subOption: {
|
|
20
|
+
subOptionA: boolean;
|
|
21
|
+
subOptionB?: boolean;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const testSettingsA: Settings = {
|
|
26
|
+
optionA: 'foo',
|
|
27
|
+
optionB: undefined, // TypeScript error if `exactOptionalPropertyTypes` is true.
|
|
28
|
+
subOption: {
|
|
29
|
+
subOptionA: true,
|
|
30
|
+
subOptionB: undefined, // TypeScript error if `exactOptionalPropertyTypes` is true
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const testSettingsB: UndefinedOnPartialDeep<Settings> = {
|
|
35
|
+
optionA: 'foo',
|
|
36
|
+
optionB: undefined, // 👉 `optionB` can be set to undefined now.
|
|
37
|
+
subOption: {
|
|
38
|
+
subOptionA: true,
|
|
39
|
+
subOptionB: undefined, // 👉 `subOptionB` can be set to undefined now.
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
*/
|
|
44
|
+
export type UndefinedOnPartialDeep<T> =
|
|
45
|
+
// Handle built-in type and function
|
|
46
|
+
T extends BuiltIns | Function
|
|
47
|
+
? T
|
|
48
|
+
// Handle tuple and array
|
|
49
|
+
: T extends readonly unknown[]
|
|
50
|
+
? UndefinedOnPartialList<T>
|
|
51
|
+
// Handle map and readonly map
|
|
52
|
+
: T extends Map<infer K, infer V>
|
|
53
|
+
? Map<K, UndefinedOnPartialDeep<V>>
|
|
54
|
+
: T extends ReadonlyMap<infer K, infer V>
|
|
55
|
+
? ReadonlyMap<K, UndefinedOnPartialDeep<V>>
|
|
56
|
+
// Handle set and readonly set
|
|
57
|
+
: T extends Set<infer K>
|
|
58
|
+
? Set<UndefinedOnPartialDeep<K>>
|
|
59
|
+
: T extends ReadonlySet<infer K>
|
|
60
|
+
? ReadonlySet<UndefinedOnPartialDeep<K>>
|
|
61
|
+
// Handle object
|
|
62
|
+
: T extends Record<any, any>
|
|
63
|
+
? {
|
|
64
|
+
[KeyType in keyof T]: undefined extends T[KeyType]
|
|
65
|
+
? UndefinedOnPartialDeep<T[KeyType]> | undefined
|
|
66
|
+
: UndefinedOnPartialDeep<T[KeyType]>
|
|
67
|
+
}
|
|
68
|
+
: T; // If T is not builtins / function / array / map / set / object, return T
|
|
69
|
+
|
|
70
|
+
// Handle tuples and arrays
|
|
71
|
+
type UndefinedOnPartialList<T extends readonly unknown[]> = T extends []
|
|
72
|
+
? []
|
|
73
|
+
: T extends [infer F, ...infer R]
|
|
74
|
+
? [UndefinedOnPartialDeep<F>, ...UndefinedOnPartialDeep<R>]
|
|
75
|
+
: T extends readonly [infer F, ...infer R]
|
|
76
|
+
? readonly [UndefinedOnPartialDeep<F>, ...UndefinedOnPartialDeep<R>]
|
|
77
|
+
: T extends Array<infer F>
|
|
78
|
+
? Array<UndefinedOnPartialDeep<F>>
|
|
79
|
+
: T extends ReadonlyArray<infer F>
|
|
80
|
+
? ReadonlyArray<UndefinedOnPartialDeep<F>>
|
|
81
|
+
: never;
|
|
@@ -38,23 +38,31 @@ export type WritableDeep<T> = T extends BuiltIns
|
|
|
38
38
|
: HasMultipleCallSignatures<T> extends true
|
|
39
39
|
? T
|
|
40
40
|
: ((...arguments_: Parameters<T>) => ReturnType<T>) & WritableObjectDeep<T>
|
|
41
|
-
: T extends
|
|
42
|
-
? WritableMapDeep<
|
|
43
|
-
: T extends
|
|
44
|
-
? WritableSetDeep<
|
|
45
|
-
: T extends
|
|
46
|
-
?
|
|
47
|
-
:
|
|
41
|
+
: T extends ReadonlyMap<unknown, unknown>
|
|
42
|
+
? WritableMapDeep<T>
|
|
43
|
+
: T extends ReadonlySet<unknown>
|
|
44
|
+
? WritableSetDeep<T>
|
|
45
|
+
: T extends readonly unknown[]
|
|
46
|
+
? WritableArrayDeep<T>
|
|
47
|
+
: T extends object
|
|
48
|
+
? WritableObjectDeep<T>
|
|
49
|
+
: unknown;
|
|
48
50
|
|
|
49
51
|
/**
|
|
50
52
|
Same as `WritableDeep`, but accepts only `Map`s as inputs. Internal helper for `WritableDeep`.
|
|
51
53
|
*/
|
|
52
|
-
type WritableMapDeep<
|
|
54
|
+
type WritableMapDeep<MapType extends ReadonlyMap<unknown, unknown>> =
|
|
55
|
+
MapType extends ReadonlyMap<infer KeyType, infer ValueType>
|
|
56
|
+
? Map<WritableDeep<KeyType>, WritableDeep<ValueType>>
|
|
57
|
+
: MapType; // Should not heppen
|
|
53
58
|
|
|
54
59
|
/**
|
|
55
60
|
Same as `WritableDeep`, but accepts only `Set`s as inputs. Internal helper for `WritableDeep`.
|
|
56
61
|
*/
|
|
57
|
-
type WritableSetDeep<
|
|
62
|
+
type WritableSetDeep<SetType extends ReadonlySet<unknown>> =
|
|
63
|
+
SetType extends ReadonlySet<infer ItemType>
|
|
64
|
+
? Set<WritableDeep<ItemType>>
|
|
65
|
+
: SetType; // Should not heppen
|
|
58
66
|
|
|
59
67
|
/**
|
|
60
68
|
Same as `WritableDeep`, but accepts only `object`s as inputs. Internal helper for `WritableDeep`.
|
|
@@ -62,3 +70,15 @@ Same as `WritableDeep`, but accepts only `object`s as inputs. Internal helper fo
|
|
|
62
70
|
type WritableObjectDeep<ObjectType extends object> = {
|
|
63
71
|
-readonly [KeyType in keyof ObjectType]: WritableDeep<ObjectType[KeyType]>
|
|
64
72
|
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
Same as `WritableDeep`, but accepts only `Array`s as inputs. Internal helper for `WritableDeep`.
|
|
76
|
+
*/
|
|
77
|
+
type WritableArrayDeep<ArrayType extends readonly unknown[]> =
|
|
78
|
+
ArrayType extends readonly [] ? []
|
|
79
|
+
: ArrayType extends readonly [...infer U, infer V] ? [...WritableArrayDeep<U>, WritableDeep<V>]
|
|
80
|
+
: ArrayType extends readonly [infer U, ...infer V] ? [WritableDeep<U>, ...WritableArrayDeep<V>]
|
|
81
|
+
: ArrayType extends ReadonlyArray<infer U> ? Array<WritableDeep<U>>
|
|
82
|
+
: ArrayType extends Array<infer U> ? Array<WritableDeep<U>>
|
|
83
|
+
: ArrayType;
|
|
84
|
+
|