@depup/type-fest 5.4.4-depup.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/README.md +25 -0
- package/index.d.ts +211 -0
- package/license-cc0 +121 -0
- package/license-mit +9 -0
- package/package.json +85 -0
- package/readme.md +1052 -0
- package/source/all-extend.d.ts +120 -0
- package/source/all-union-fields.d.ts +91 -0
- package/source/and.d.ts +81 -0
- package/source/array-element.d.ts +46 -0
- package/source/array-indices.d.ts +25 -0
- package/source/array-reverse.d.ts +84 -0
- package/source/array-slice.d.ts +132 -0
- package/source/array-splice.d.ts +104 -0
- package/source/array-tail.d.ts +70 -0
- package/source/array-values.d.ts +24 -0
- package/source/arrayable.d.ts +31 -0
- package/source/async-return-type.d.ts +28 -0
- package/source/asyncify.d.ts +25 -0
- package/source/basic.d.ts +38 -0
- package/source/camel-case.d.ts +92 -0
- package/source/camel-cased-properties-deep.d.ts +99 -0
- package/source/camel-cased-properties.d.ts +45 -0
- package/source/characters.d.ts +67 -0
- package/source/conditional-except.d.ts +47 -0
- package/source/conditional-keys.d.ts +63 -0
- package/source/conditional-pick-deep.d.ts +120 -0
- package/source/conditional-pick.d.ts +46 -0
- package/source/conditional-simplify-deep.d.ts +73 -0
- package/source/conditional-simplify.d.ts +50 -0
- package/source/delimiter-case.d.ts +77 -0
- package/source/delimiter-cased-properties-deep.d.ts +108 -0
- package/source/delimiter-cased-properties.d.ts +48 -0
- package/source/distributed-omit.d.ts +96 -0
- package/source/distributed-pick.d.ts +92 -0
- package/source/empty-object.d.ts +51 -0
- package/source/entries.d.ts +64 -0
- package/source/entry.d.ts +67 -0
- package/source/exact.d.ts +73 -0
- package/source/except.d.ts +112 -0
- package/source/exclude-rest-element.d.ts +40 -0
- package/source/exclude-strict.d.ts +51 -0
- package/source/exclusify-union.d.ts +147 -0
- package/source/extends-strict.d.ts +44 -0
- package/source/extract-rest-element.d.ts +30 -0
- package/source/extract-strict.d.ts +51 -0
- package/source/find-global-type.d.ts +68 -0
- package/source/fixed-length-array.d.ts +97 -0
- package/source/get.d.ts +227 -0
- package/source/global-this.d.ts +24 -0
- package/source/globals/index.d.ts +3 -0
- package/source/globals/observable-like.d.ts +78 -0
- package/source/greater-than-or-equal.d.ts +30 -0
- package/source/greater-than.d.ts +58 -0
- package/source/has-optional-keys.d.ts +23 -0
- package/source/has-readonly-keys.d.ts +23 -0
- package/source/has-required-keys.d.ts +61 -0
- package/source/has-writable-keys.d.ts +23 -0
- package/source/if-any.d.ts +28 -0
- package/source/if-empty-object.d.ts +30 -0
- package/source/if-never.d.ts +28 -0
- package/source/if-null.d.ts +28 -0
- package/source/if-unknown.d.ts +28 -0
- package/source/if.d.ts +102 -0
- package/source/includes.d.ts +24 -0
- package/source/int-closed-range.d.ts +47 -0
- package/source/int-range.d.ts +69 -0
- package/source/internal/array.d.ts +151 -0
- package/source/internal/characters.d.ts +65 -0
- package/source/internal/enforce-optional.d.ts +49 -0
- package/source/internal/index.d.ts +11 -0
- package/source/internal/keys.d.ts +100 -0
- package/source/internal/numeric.d.ts +151 -0
- package/source/internal/object.d.ts +292 -0
- package/source/internal/string.d.ts +202 -0
- package/source/internal/tuple.d.ts +79 -0
- package/source/internal/type.d.ts +164 -0
- package/source/invariant-of.d.ts +85 -0
- package/source/is-any.d.ts +31 -0
- package/source/is-equal.d.ts +42 -0
- package/source/is-float.d.ts +43 -0
- package/source/is-integer.d.ts +60 -0
- package/source/is-literal.d.ts +315 -0
- package/source/is-lowercase.d.ts +38 -0
- package/source/is-never.d.ts +56 -0
- package/source/is-null.d.ts +22 -0
- package/source/is-nullable.d.ts +30 -0
- package/source/is-optional-key-of.d.ts +51 -0
- package/source/is-optional.d.ts +28 -0
- package/source/is-readonly-key-of.d.ts +55 -0
- package/source/is-required-key-of.d.ts +51 -0
- package/source/is-tuple.d.ts +92 -0
- package/source/is-undefined.d.ts +22 -0
- package/source/is-union.d.ts +40 -0
- package/source/is-unknown.d.ts +43 -0
- package/source/is-uppercase.d.ts +38 -0
- package/source/is-writable-key-of.d.ts +51 -0
- package/source/iterable-element.d.ts +66 -0
- package/source/join.d.ts +79 -0
- package/source/json-value.d.ts +33 -0
- package/source/jsonifiable.d.ts +37 -0
- package/source/jsonify.d.ts +127 -0
- package/source/kebab-case.d.ts +46 -0
- package/source/kebab-cased-properties-deep.d.ts +65 -0
- package/source/kebab-cased-properties.d.ts +42 -0
- package/source/key-as-string.d.ts +27 -0
- package/source/keys-of-union.d.ts +44 -0
- package/source/last-array-element.d.ts +36 -0
- package/source/less-than-or-equal.d.ts +24 -0
- package/source/less-than.d.ts +28 -0
- package/source/literal-to-primitive-deep.d.ts +71 -0
- package/source/literal-to-primitive.d.ts +38 -0
- package/source/literal-union.d.ts +39 -0
- package/source/merge-deep.d.ts +495 -0
- package/source/merge-exclusive.d.ts +45 -0
- package/source/merge.d.ts +62 -0
- package/source/multidimensional-array.d.ts +38 -0
- package/source/multidimensional-readonly-array.d.ts +38 -0
- package/source/non-empty-object.d.ts +38 -0
- package/source/non-empty-string.d.ts +32 -0
- package/source/non-empty-tuple.d.ts +24 -0
- package/source/numeric.d.ts +226 -0
- package/source/object-merge.d.ts +194 -0
- package/source/omit-deep.d.ts +154 -0
- package/source/omit-index-signature.d.ts +98 -0
- package/source/opaque.d.ts +3 -0
- package/source/optional-keys-of.d.ts +46 -0
- package/source/or.d.ts +89 -0
- package/source/override-properties.d.ts +43 -0
- package/source/package-json.d.ts +710 -0
- package/source/partial-deep.d.ts +155 -0
- package/source/partial-on-undefined-deep.d.ts +81 -0
- package/source/pascal-case.d.ts +51 -0
- package/source/pascal-cased-properties-deep.d.ts +72 -0
- package/source/pascal-cased-properties.d.ts +42 -0
- package/source/paths.d.ts +241 -0
- package/source/pick-deep.d.ts +152 -0
- package/source/pick-index-signature.d.ts +52 -0
- package/source/primitive.d.ts +15 -0
- package/source/promisable.d.ts +27 -0
- package/source/readonly-deep.d.ts +116 -0
- package/source/readonly-keys-of.d.ts +38 -0
- package/source/readonly-tuple.d.ts +34 -0
- package/source/remove-prefix.d.ts +132 -0
- package/source/replace.d.ts +87 -0
- package/source/require-all-or-none.d.ts +54 -0
- package/source/require-at-least-one.d.ts +50 -0
- package/source/require-exactly-one.d.ts +48 -0
- package/source/require-one-or-none.d.ts +49 -0
- package/source/required-deep.d.ts +76 -0
- package/source/required-keys-of.d.ts +38 -0
- package/source/schema.d.ts +119 -0
- package/source/screaming-snake-case.d.ts +30 -0
- package/source/set-field-type.d.ts +67 -0
- package/source/set-non-nullable-deep.d.ts +85 -0
- package/source/set-non-nullable.d.ts +41 -0
- package/source/set-optional.d.ts +46 -0
- package/source/set-parameter-type.d.ts +125 -0
- package/source/set-readonly.d.ts +44 -0
- package/source/set-required-deep.d.ts +64 -0
- package/source/set-required.d.ts +79 -0
- package/source/set-return-type.d.ts +31 -0
- package/source/shared-union-fields-deep.d.ts +180 -0
- package/source/shared-union-fields.d.ts +79 -0
- package/source/simplify-deep.d.ts +117 -0
- package/source/simplify.d.ts +61 -0
- package/source/single-key-object.d.ts +28 -0
- package/source/snake-case.d.ts +47 -0
- package/source/snake-cased-properties-deep.d.ts +65 -0
- package/source/snake-cased-properties.d.ts +42 -0
- package/source/split-on-rest-element.d.ts +106 -0
- package/source/split.d.ts +90 -0
- package/source/spread.d.ts +82 -0
- package/source/string-repeat.d.ts +49 -0
- package/source/string-slice.d.ts +39 -0
- package/source/stringified.d.ts +25 -0
- package/source/structured-cloneable.d.ts +89 -0
- package/source/subtract.d.ts +86 -0
- package/source/sum.d.ts +81 -0
- package/source/tagged-union.d.ts +53 -0
- package/source/tagged.d.ts +263 -0
- package/source/trim.d.ts +29 -0
- package/source/tsconfig-json.d.ts +1324 -0
- package/source/tuple-of.d.ts +80 -0
- package/source/tuple-to-object.d.ts +47 -0
- package/source/tuple-to-union.d.ts +54 -0
- package/source/typed-array.d.ts +19 -0
- package/source/undefined-on-partial-deep.d.ts +83 -0
- package/source/union-to-intersection.d.ts +35 -0
- package/source/union-to-tuple.d.ts +58 -0
- package/source/unknown-array.d.ts +27 -0
- package/source/unknown-map.d.ts +26 -0
- package/source/unknown-record.d.ts +33 -0
- package/source/unknown-set.d.ts +26 -0
- package/source/unwrap-partial.d.ts +33 -0
- package/source/value-of.d.ts +24 -0
- package/source/words.d.ts +122 -0
- package/source/writable-deep.d.ts +84 -0
- package/source/writable-keys-of.d.ts +34 -0
- package/source/writable.d.ts +72 -0
- package/source/xor.d.ts +83 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type {If} from './if.d.ts';
|
|
2
|
+
import type {IfNotAnyOrNever, MapsSetsOrArrays, NonRecursiveType} from './internal/type.d.ts';
|
|
3
|
+
import type {IsUnknown} from './is-unknown.d.ts';
|
|
4
|
+
import type {KeysOfUnion} from './keys-of-union.d.ts';
|
|
5
|
+
import type {Simplify} from './simplify.d.ts';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
Ensure mutual exclusivity in object unions by adding other members’ keys as `?: never`.
|
|
9
|
+
|
|
10
|
+
Use-cases:
|
|
11
|
+
- You want each union member to be exclusive, preventing overlapping object shapes.
|
|
12
|
+
- You want to safely access any property defined across the union without additional type guards.
|
|
13
|
+
|
|
14
|
+
@example
|
|
15
|
+
```
|
|
16
|
+
import type {ExclusifyUnion} from 'type-fest';
|
|
17
|
+
|
|
18
|
+
type FileConfig = {
|
|
19
|
+
filePath: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type InlineConfig = {
|
|
23
|
+
content: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
declare function loadConfig1(options: FileConfig | InlineConfig): void;
|
|
27
|
+
|
|
28
|
+
// Someone could mistakenly provide both `filePath` and `content`.
|
|
29
|
+
loadConfig1({filePath: './config.json', content: '{ "name": "app" }'}); // No errors
|
|
30
|
+
|
|
31
|
+
// Use `ExclusifyUnion` to prevent that mistake.
|
|
32
|
+
type Config = ExclusifyUnion<FileConfig | InlineConfig>;
|
|
33
|
+
//=> {
|
|
34
|
+
// filePath: string;
|
|
35
|
+
// content?: never;
|
|
36
|
+
// } | {
|
|
37
|
+
// content: string;
|
|
38
|
+
// filePath?: never;
|
|
39
|
+
// }
|
|
40
|
+
|
|
41
|
+
declare function loadConfig2(options: Config): void;
|
|
42
|
+
|
|
43
|
+
// @ts-expect-error
|
|
44
|
+
loadConfig2({filePath: './config.json', content: '{ "name": "app" }'});
|
|
45
|
+
// Error: Argument of type '{ filePath: string; content: string; }' is not assignable to parameter of type '{ filePath: string; content?: never; } | { content: string; filePath?: never; }'.
|
|
46
|
+
|
|
47
|
+
loadConfig2({filePath: './config.json'}); // Ok
|
|
48
|
+
|
|
49
|
+
loadConfig2({content: '{ "name": "app" }'}); // Ok
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
@example
|
|
53
|
+
```
|
|
54
|
+
import type {ExclusifyUnion} from 'type-fest';
|
|
55
|
+
|
|
56
|
+
type CardPayment = {
|
|
57
|
+
amount: number;
|
|
58
|
+
cardNumber: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
type PaypalPayment = {
|
|
62
|
+
amount: number;
|
|
63
|
+
paypalId: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function processPayment1(payment: CardPayment | PaypalPayment) {
|
|
67
|
+
// @ts-expect-error
|
|
68
|
+
const details = payment.cardNumber ?? payment.paypalId; // Cannot access `cardNumber` or `paypalId` directly
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
type Payment = ExclusifyUnion<CardPayment | PaypalPayment>;
|
|
72
|
+
//=> {
|
|
73
|
+
// amount: number;
|
|
74
|
+
// cardNumber: string;
|
|
75
|
+
// paypalId?: never;
|
|
76
|
+
// } | {
|
|
77
|
+
// amount: number;
|
|
78
|
+
// paypalId: string;
|
|
79
|
+
// cardNumber?: never;
|
|
80
|
+
// }
|
|
81
|
+
|
|
82
|
+
function processPayment2(payment: Payment) {
|
|
83
|
+
const details = payment.cardNumber ?? payment.paypalId; // Ok
|
|
84
|
+
//=> string
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
@example
|
|
89
|
+
```
|
|
90
|
+
import type {ExclusifyUnion} from 'type-fest';
|
|
91
|
+
|
|
92
|
+
type A = ExclusifyUnion<{a: string} | {b: number}>;
|
|
93
|
+
//=> {a: string; b?: never} | {b: number; a?: never}
|
|
94
|
+
|
|
95
|
+
type B = ExclusifyUnion<{a: string} | {b: number} | {c: boolean}>;
|
|
96
|
+
//=> {
|
|
97
|
+
// a: string;
|
|
98
|
+
// b?: never;
|
|
99
|
+
// c?: never;
|
|
100
|
+
// } | {
|
|
101
|
+
// b: number;
|
|
102
|
+
// a?: never;
|
|
103
|
+
// c?: never;
|
|
104
|
+
// } | {
|
|
105
|
+
// c: boolean;
|
|
106
|
+
// a?: never;
|
|
107
|
+
// b?: never;
|
|
108
|
+
// }
|
|
109
|
+
|
|
110
|
+
type C = ExclusifyUnion<{a: string; b: number} | {b: string; c: number}>;
|
|
111
|
+
//=> {
|
|
112
|
+
// a: string;
|
|
113
|
+
// b: number;
|
|
114
|
+
// c?: never;
|
|
115
|
+
// } | {
|
|
116
|
+
// b: string;
|
|
117
|
+
// c: number;
|
|
118
|
+
// a?: never;
|
|
119
|
+
// }
|
|
120
|
+
|
|
121
|
+
type D = ExclusifyUnion<{a?: 1; readonly b: 2} | {d: 4}>;
|
|
122
|
+
//=> {a?: 1; readonly b: 2; d?: never} | {d: 4; a?: never; b?: never}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
@category Object
|
|
126
|
+
@category Union
|
|
127
|
+
*/
|
|
128
|
+
export type ExclusifyUnion<Union> = IfNotAnyOrNever<Union,
|
|
129
|
+
If<IsUnknown<Union>, Union,
|
|
130
|
+
Extract<Union, NonRecursiveType | MapsSetsOrArrays> extends infer SkippedMembers
|
|
131
|
+
? SkippedMembers | _ExclusifyUnion<Exclude<Union, SkippedMembers>>
|
|
132
|
+
: never
|
|
133
|
+
>
|
|
134
|
+
>;
|
|
135
|
+
|
|
136
|
+
type _ExclusifyUnion<Union, UnionCopy = Union> = Union extends unknown // For distributing `Union`
|
|
137
|
+
? Simplify<
|
|
138
|
+
Union & Partial<
|
|
139
|
+
Record<
|
|
140
|
+
Exclude<KeysOfUnion<UnionCopy>, keyof Union>,
|
|
141
|
+
never
|
|
142
|
+
>
|
|
143
|
+
>
|
|
144
|
+
>
|
|
145
|
+
: never; // Should never happen
|
|
146
|
+
|
|
147
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type {IsNever} from './is-never.d.ts';
|
|
2
|
+
import type {IsAny} from './is-any.d.ts';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
A stricter, non-distributive version of `extends` for checking whether one type is assignable to another.
|
|
6
|
+
|
|
7
|
+
Unlike the built-in `extends` keyword, `ExtendsStrict`:
|
|
8
|
+
|
|
9
|
+
1. Prevents distribution over union types by wrapping both types in tuples. For example, `ExtendsStrict<string | number, number>` returns `false`, whereas `string | number extends number` would result in `boolean`.
|
|
10
|
+
|
|
11
|
+
2. Treats `never` as a special case: `never` doesn't extend every other type, it only extends itself (or `any`). For example, `ExtendsStrict<never, number>` returns `false` whereas `never extends number` would result in `true`.
|
|
12
|
+
|
|
13
|
+
@example
|
|
14
|
+
```
|
|
15
|
+
import type {ExtendsStrict} from 'type-fest';
|
|
16
|
+
|
|
17
|
+
type T1 = ExtendsStrict<number | string, string>;
|
|
18
|
+
//=> false
|
|
19
|
+
|
|
20
|
+
type T2 = ExtendsStrict<never, number>;
|
|
21
|
+
//=> false
|
|
22
|
+
|
|
23
|
+
type T3 = ExtendsStrict<never, never>;
|
|
24
|
+
//=> true
|
|
25
|
+
|
|
26
|
+
type T4 = ExtendsStrict<string, number | string>;
|
|
27
|
+
//=> true
|
|
28
|
+
|
|
29
|
+
type T5 = ExtendsStrict<string, string>;
|
|
30
|
+
//=> true
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
@category Improved Built-in
|
|
34
|
+
*/
|
|
35
|
+
export type ExtendsStrict<Left, Right> =
|
|
36
|
+
IsAny<Left | Right> extends true
|
|
37
|
+
? true
|
|
38
|
+
: IsNever<Left> extends true
|
|
39
|
+
? IsNever<Right>
|
|
40
|
+
: [Left] extends [Right]
|
|
41
|
+
? true
|
|
42
|
+
: false;
|
|
43
|
+
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type {SplitOnRestElement} from './split-on-rest-element.d.ts';
|
|
2
|
+
import type {UnknownArray} from './unknown-array.d.ts';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
Extract the [`rest`](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) element type from an array.
|
|
6
|
+
|
|
7
|
+
@example
|
|
8
|
+
```
|
|
9
|
+
import type {ExtractRestElement} from 'type-fest';
|
|
10
|
+
|
|
11
|
+
type T1 = ExtractRestElement<[number, ...string[], string, 'foo']>;
|
|
12
|
+
//=> string
|
|
13
|
+
|
|
14
|
+
type T2 = ExtractRestElement<[...boolean[], string]>;
|
|
15
|
+
//=> boolean
|
|
16
|
+
|
|
17
|
+
type T3 = ExtractRestElement<[...Array<'foo'>, true]>;
|
|
18
|
+
//=> 'foo'
|
|
19
|
+
|
|
20
|
+
type T4 = ExtractRestElement<[number, string]>;
|
|
21
|
+
//=> never
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
@see {@link ExcludeRestElement}
|
|
25
|
+
@see {@link SplitOnRestElement}
|
|
26
|
+
@category Array
|
|
27
|
+
*/
|
|
28
|
+
export type ExtractRestElement<T extends UnknownArray> = SplitOnRestElement<T>[1][number];
|
|
29
|
+
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
A stricter version of {@link Extract<T, U>} that ensures every member of `U` can successfully extract something from `T`.
|
|
3
|
+
|
|
4
|
+
For example, `ExtractStrict<string | number | boolean, number | bigint>` will error because `bigint` cannot extract anything from `string | number | boolean`.
|
|
5
|
+
|
|
6
|
+
@example
|
|
7
|
+
```
|
|
8
|
+
// Valid Examples
|
|
9
|
+
import type {ExtractStrict} from 'type-fest';
|
|
10
|
+
|
|
11
|
+
type Example1 = ExtractStrict<{status: 'success'; data: string[]} | {status: 'error'; error: string}, {status: 'success'}>;
|
|
12
|
+
//=> {status: 'success'; data: string[]}
|
|
13
|
+
|
|
14
|
+
type Example2 = ExtractStrict<'xs' | 's' | 'm' | 'l' | 'xl', 'xs' | 's'>;
|
|
15
|
+
//=> 'xs' | 's'
|
|
16
|
+
|
|
17
|
+
type Example3 = ExtractStrict<{x: number; y: number} | [number, number], unknown[]>;
|
|
18
|
+
//=> [number, number]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
@example
|
|
22
|
+
```
|
|
23
|
+
// Invalid Examples
|
|
24
|
+
import type {ExtractStrict} from 'type-fest';
|
|
25
|
+
|
|
26
|
+
// `'xxl'` cannot extract anything from `'xs' | 's' | 'm' | 'l' | 'xl'`
|
|
27
|
+
// @ts-expect-error
|
|
28
|
+
type Example1 = ExtractStrict<'xs' | 's' | 'm' | 'l' | 'xl', 'xl' | 'xxl'>;
|
|
29
|
+
// ~~~~~~~~~~~~
|
|
30
|
+
// Error: Type "'xl' | 'xxl'" does not satisfy the constraint 'never'.
|
|
31
|
+
|
|
32
|
+
// `unknown[]` cannot extract anything from `{x: number; y: number} | {x: string; y: string}`
|
|
33
|
+
// @ts-expect-error
|
|
34
|
+
type Example2 = ExtractStrict<{x: number; y: number} | {x: string; y: string}, unknown[]>;
|
|
35
|
+
// ~~~~~~~~~
|
|
36
|
+
// Error: Type 'unknown[]' does not satisfy the constraint 'never'.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
@category Improved Built-in
|
|
40
|
+
*/
|
|
41
|
+
export type ExtractStrict<
|
|
42
|
+
T,
|
|
43
|
+
U extends [U] extends [
|
|
44
|
+
// Ensure every member of `U` extracts something from `T`
|
|
45
|
+
U extends unknown ? (Extract<T, U> extends never ? never : U) : never,
|
|
46
|
+
]
|
|
47
|
+
? unknown
|
|
48
|
+
: never,
|
|
49
|
+
> = Extract<T, U>;
|
|
50
|
+
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Tries to find the type of a global with the given name.
|
|
3
|
+
|
|
4
|
+
Limitations: Due to peculiarities with the behavior of `globalThis`, "globally defined" only includes `var` declarations in `declare global` blocks, not `let` or `const` declarations.
|
|
5
|
+
|
|
6
|
+
@example
|
|
7
|
+
```
|
|
8
|
+
import type {FindGlobalType} from 'type-fest';
|
|
9
|
+
|
|
10
|
+
declare global {
|
|
11
|
+
const foo: number; // let and const don't work
|
|
12
|
+
var bar: string; // var works
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type FooType = FindGlobalType<'foo'>; //=> never (let/const don't work)
|
|
16
|
+
type BarType = FindGlobalType<'bar'>; //=> string
|
|
17
|
+
type OtherType = FindGlobalType<'other'>; //=> never (no global named 'other')
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
@category Utilities
|
|
21
|
+
*/
|
|
22
|
+
export type FindGlobalType<Name extends string> = typeof globalThis extends Record<Name, infer T> ? T : never;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
Tries to find one or more types from their globally-defined constructors.
|
|
26
|
+
|
|
27
|
+
Use-case: Conditionally referencing DOM types only when the DOM library present.
|
|
28
|
+
|
|
29
|
+
*Limitations:* Due to peculiarities with the behavior of `globalThis`, "globally defined" has a narrow definition in this case. Declaring a class in a `declare global` block won't work, instead you must declare its type using an interface and declare its constructor as a `var` (*not* `let`/`const`) inside the `declare global` block.
|
|
30
|
+
|
|
31
|
+
@example
|
|
32
|
+
```
|
|
33
|
+
import type {FindGlobalInstanceType} from 'type-fest';
|
|
34
|
+
|
|
35
|
+
class Point {
|
|
36
|
+
constructor(public x: number, public y: number) {}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type PointLike = Point | FindGlobalInstanceType<'DOMPoint'>;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
@example
|
|
43
|
+
```
|
|
44
|
+
import type {FindGlobalInstanceType} from 'type-fest';
|
|
45
|
+
|
|
46
|
+
declare global {
|
|
47
|
+
// Class syntax won't add the key to `globalThis`
|
|
48
|
+
class Foo {}
|
|
49
|
+
|
|
50
|
+
// interface + constructor style works
|
|
51
|
+
interface Bar {
|
|
52
|
+
bar: string;
|
|
53
|
+
}
|
|
54
|
+
var Bar: new () => Bar; // Not let or const
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type FindFoo = FindGlobalInstanceType<'Foo'>; // Doesn't work
|
|
58
|
+
type FindBar = FindGlobalInstanceType<'Bar'>; // Works
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
@category Utilities
|
|
62
|
+
*/
|
|
63
|
+
export type FindGlobalInstanceType<Name extends string> =
|
|
64
|
+
Name extends string
|
|
65
|
+
? typeof globalThis extends Record<Name, abstract new (...arguments_: any[]) => infer T> ? T : never
|
|
66
|
+
: never;
|
|
67
|
+
|
|
68
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type {Except} from './except.d.ts';
|
|
2
|
+
import type {TupleOf} from './tuple-of.d.ts';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
Methods to exclude.
|
|
6
|
+
*/
|
|
7
|
+
type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' | 'unshift';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
Create a type that represents an array of the given type and length. The `Array` prototype methods that manipulate its length are excluded from the resulting type.
|
|
11
|
+
|
|
12
|
+
The problem with the built-in tuple type is that it allows mutating methods like `push`, `pop` etc, which can cause issues, like in the following example:
|
|
13
|
+
|
|
14
|
+
@example
|
|
15
|
+
```
|
|
16
|
+
const color: [number, number, number] = [255, 128, 64];
|
|
17
|
+
|
|
18
|
+
function toHex([r, g, b]: readonly [number, number, number]) {
|
|
19
|
+
return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
color.pop(); // Allowed
|
|
23
|
+
|
|
24
|
+
console.log(toHex(color)); // Compiles fine, but fails at runtime since index `2` no longer contains a `number`.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`ArrayLengthMutationKeys` solves this problem by excluding methods like `push`, `pop` etc from the resulting type.
|
|
28
|
+
|
|
29
|
+
@example
|
|
30
|
+
```
|
|
31
|
+
import type {FixedLengthArray} from 'type-fest';
|
|
32
|
+
|
|
33
|
+
const color: FixedLengthArray<number, 3> = [255, 128, 64];
|
|
34
|
+
|
|
35
|
+
// @ts-expect-error
|
|
36
|
+
color.pop();
|
|
37
|
+
// Error: Property 'pop' does not exist on type 'FixedLengthArray<number, 3>'.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use-cases:
|
|
41
|
+
- Declaring fixed-length tuples or arrays with a large number of items.
|
|
42
|
+
- Creating an array of coordinates with a static length, for example, length of 3 for a 3D vector.
|
|
43
|
+
|
|
44
|
+
@example
|
|
45
|
+
```
|
|
46
|
+
import type {FixedLengthArray} from 'type-fest';
|
|
47
|
+
|
|
48
|
+
let color: FixedLengthArray<number, 3> = [255, 128, 64];
|
|
49
|
+
|
|
50
|
+
const red = color[0];
|
|
51
|
+
//=> number
|
|
52
|
+
const green = color[1];
|
|
53
|
+
//=> number
|
|
54
|
+
const blue = color[2];
|
|
55
|
+
//=> number
|
|
56
|
+
|
|
57
|
+
// @ts-expect-error
|
|
58
|
+
const alpha = color[3];
|
|
59
|
+
// Error: Property '3' does not exist on type 'FixedLengthArray<number, 3>'.
|
|
60
|
+
|
|
61
|
+
// You can write to valid indices.
|
|
62
|
+
color[0] = 128;
|
|
63
|
+
color[1] = 64;
|
|
64
|
+
color[2] = 32;
|
|
65
|
+
|
|
66
|
+
// But you cannot write to out-of-bounds indices.
|
|
67
|
+
// @ts-expect-error
|
|
68
|
+
color[3] = 0.5;
|
|
69
|
+
// Error: Property '3' does not exist on type 'FixedLengthArray<number, 3>'.
|
|
70
|
+
|
|
71
|
+
// @ts-expect-error
|
|
72
|
+
color.push(0.5);
|
|
73
|
+
// Error: Property 'push' does not exist on type 'FixedLengthArray<number, 3>'.
|
|
74
|
+
|
|
75
|
+
// @ts-expect-error
|
|
76
|
+
color = [0, 128, 255, 0.5];
|
|
77
|
+
// Error: Type '[number, number, number, number]' is not assignable to type 'FixedLengthArray<number, 3>'. Types of property 'length' are incompatible.
|
|
78
|
+
|
|
79
|
+
// @ts-expect-error
|
|
80
|
+
color.length = 4;
|
|
81
|
+
// Error: Cannot assign to 'length' because it is a read-only property.
|
|
82
|
+
|
|
83
|
+
function toHex([r, g, b]: readonly [number, number, number]) {
|
|
84
|
+
return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(toHex(color)); // `FixedLengthArray<number, 3>` is assignable to `readonly [number, number, number]`.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
@category Array
|
|
91
|
+
*/
|
|
92
|
+
export type FixedLengthArray<Element, Length extends number> =
|
|
93
|
+
Except<TupleOf<Length, Element>, ArrayLengthMutationKeys | number | 'length'>
|
|
94
|
+
& {readonly length: Length}
|
|
95
|
+
& (number extends Length ? {[n: number]: Element} : {}); // Add `number` index signature only for non-tuple arrays.
|
|
96
|
+
|
|
97
|
+
export {};
|
package/source/get.d.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import type {ApplyDefaultOptions, ToString} from './internal/index.d.ts';
|
|
2
|
+
import type {_LiteralStringUnion} from './literal-union.d.ts';
|
|
3
|
+
import type {Paths} from './paths.d.ts';
|
|
4
|
+
import type {Split} from './split.d.ts';
|
|
5
|
+
import type {KeyAsString} from './key-as-string.d.ts';
|
|
6
|
+
import type {DigitCharacter} from './characters.d.ts';
|
|
7
|
+
|
|
8
|
+
export type GetOptions = {
|
|
9
|
+
/**
|
|
10
|
+
Include `undefined` in the return type when accessing properties.
|
|
11
|
+
|
|
12
|
+
Setting this to `false` is not recommended.
|
|
13
|
+
|
|
14
|
+
@default true
|
|
15
|
+
*/
|
|
16
|
+
strict?: boolean;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type DefaultGetOptions = {
|
|
20
|
+
strict: true;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
Like the `Get` type but receives an array of strings as a path parameter.
|
|
25
|
+
*/
|
|
26
|
+
type GetWithPath<BaseType, Keys, Options extends Required<GetOptions>> =
|
|
27
|
+
Keys extends readonly []
|
|
28
|
+
? BaseType
|
|
29
|
+
: Keys extends readonly [infer Head, ...infer Tail]
|
|
30
|
+
? GetWithPath<
|
|
31
|
+
PropertyOf<BaseType, Extract<Head, string>, Options>,
|
|
32
|
+
Extract<Tail, string[]>,
|
|
33
|
+
Options
|
|
34
|
+
>
|
|
35
|
+
: never;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
Adds `undefined` to `Type` if `strict` is enabled.
|
|
39
|
+
*/
|
|
40
|
+
type Strictify<Type, Options extends Required<GetOptions>> =
|
|
41
|
+
Options['strict'] extends false ? Type : (Type | undefined);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
If `Options['strict']` is `true`, includes `undefined` in the returned type when accessing properties on `Record<string, any>`.
|
|
45
|
+
|
|
46
|
+
Known limitations:
|
|
47
|
+
- Does not include `undefined` in the type on object types with an index signature (for example, `{a: string; [key: string]: string}`).
|
|
48
|
+
*/
|
|
49
|
+
type StrictPropertyOf<BaseType, Key extends keyof BaseType, Options extends Required<GetOptions>> =
|
|
50
|
+
Record<string, any> extends BaseType
|
|
51
|
+
? string extends keyof BaseType
|
|
52
|
+
? Strictify<BaseType[Key], Options> // Record<string, any>
|
|
53
|
+
: BaseType[Key] // Record<'a' | 'b', any> (Records with a string union as keys have required properties)
|
|
54
|
+
: BaseType[Key];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
Splits a dot-prop style path into a tuple comprised of the properties in the path. Handles square-bracket notation.
|
|
58
|
+
|
|
59
|
+
@example
|
|
60
|
+
```
|
|
61
|
+
type A = ToPath<'foo.bar.baz'>;
|
|
62
|
+
//=> ['foo', 'bar', 'baz']
|
|
63
|
+
|
|
64
|
+
type B = ToPath<'foo[0].bar.baz'>;
|
|
65
|
+
//=> ['foo', '0', 'bar', 'baz']
|
|
66
|
+
```
|
|
67
|
+
*/
|
|
68
|
+
type ToPath<S extends string> = Split<FixPathSquareBrackets<S>, '.', {strictLiteralChecks: false}>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
Replaces square-bracketed dot notation with dots, for example, `foo[0].bar` -> `foo.0.bar`.
|
|
72
|
+
*/
|
|
73
|
+
type FixPathSquareBrackets<Path extends string> =
|
|
74
|
+
Path extends `[${infer Head}]${infer Tail}`
|
|
75
|
+
? Tail extends `[${string}`
|
|
76
|
+
? `${Head}.${FixPathSquareBrackets<Tail>}`
|
|
77
|
+
: `${Head}${FixPathSquareBrackets<Tail>}`
|
|
78
|
+
: Path extends `${infer Head}[${infer Middle}]${infer Tail}`
|
|
79
|
+
? `${Head}.${FixPathSquareBrackets<`[${Middle}]${Tail}`>}`
|
|
80
|
+
: Path;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
Returns true if `LongString` is made up out of `Substring` repeated 0 or more times.
|
|
84
|
+
|
|
85
|
+
@example
|
|
86
|
+
```
|
|
87
|
+
type A = ConsistsOnlyOf<'aaa', 'a'>; //=> true
|
|
88
|
+
type B = ConsistsOnlyOf<'ababab', 'ab'>; //=> true
|
|
89
|
+
type C = ConsistsOnlyOf<'aBa', 'a'>; //=> false
|
|
90
|
+
type D = ConsistsOnlyOf<'', 'a'>; //=> true
|
|
91
|
+
```
|
|
92
|
+
*/
|
|
93
|
+
type ConsistsOnlyOf<LongString extends string, Substring extends string> =
|
|
94
|
+
LongString extends ''
|
|
95
|
+
? true
|
|
96
|
+
: LongString extends `${Substring}${infer Tail}`
|
|
97
|
+
? ConsistsOnlyOf<Tail, Substring>
|
|
98
|
+
: false;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
Convert a type which may have number keys to one with string keys, making it possible to index using strings retrieved from template types.
|
|
102
|
+
|
|
103
|
+
@example
|
|
104
|
+
```
|
|
105
|
+
type WithNumbers = {foo: string; 0: boolean};
|
|
106
|
+
type WithStrings = WithStringKeys<WithNumbers>;
|
|
107
|
+
|
|
108
|
+
type WithNumbersKeys = keyof WithNumbers;
|
|
109
|
+
//=> 'foo' | 0
|
|
110
|
+
type WithStringsKeys = keyof WithStrings;
|
|
111
|
+
//=> 'foo' | '0'
|
|
112
|
+
```
|
|
113
|
+
*/
|
|
114
|
+
type WithStringKeys<BaseType> = {
|
|
115
|
+
[Key in KeyAsString<BaseType>]: UncheckedIndex<BaseType, Key>
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
Perform a `T[U]` operation if `T` supports indexing.
|
|
120
|
+
*/
|
|
121
|
+
type UncheckedIndex<T, U extends string | number> = [T] extends [Record<string | number, any>] ? T[U] : never;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
Get a property of an object or array. Works when indexing arrays using number-literal-strings, for example, `PropertyOf<number[], '0'> = number`, and when indexing objects with number keys.
|
|
125
|
+
|
|
126
|
+
Note:
|
|
127
|
+
- Returns `unknown` if `Key` is not a property of `BaseType`, since TypeScript uses structural typing, and it cannot be guaranteed that extra properties unknown to the type system will exist at runtime.
|
|
128
|
+
- Returns `undefined` from nullish values, to match the behaviour of most deep-key libraries like `lodash`, `dot-prop`, etc.
|
|
129
|
+
*/
|
|
130
|
+
type PropertyOf<BaseType, Key extends string, Options extends Required<GetOptions>> =
|
|
131
|
+
BaseType extends null | undefined
|
|
132
|
+
? undefined
|
|
133
|
+
: Key extends keyof BaseType
|
|
134
|
+
? StrictPropertyOf<BaseType, Key, Options>
|
|
135
|
+
// Handle arrays and tuples
|
|
136
|
+
: BaseType extends readonly unknown[]
|
|
137
|
+
? Key extends `${number}`
|
|
138
|
+
// For arrays with unknown length (regular arrays)
|
|
139
|
+
? number extends BaseType['length']
|
|
140
|
+
? Strictify<BaseType[number], Options>
|
|
141
|
+
// For tuples: check if the index is valid
|
|
142
|
+
: Key extends keyof BaseType
|
|
143
|
+
? Strictify<BaseType[Key & keyof BaseType], Options>
|
|
144
|
+
// Out-of-bounds access for tuples
|
|
145
|
+
: unknown
|
|
146
|
+
// Non-numeric string key for arrays/tuples
|
|
147
|
+
: unknown
|
|
148
|
+
// Handle array-like objects
|
|
149
|
+
: BaseType extends {
|
|
150
|
+
[n: number]: infer Item;
|
|
151
|
+
length: number; // Note: This is needed to avoid being too lax with records types using number keys like `{0: string; 1: boolean}`.
|
|
152
|
+
}
|
|
153
|
+
? (
|
|
154
|
+
ConsistsOnlyOf<Key, DigitCharacter> extends true
|
|
155
|
+
? Strictify<Item, Options>
|
|
156
|
+
: unknown
|
|
157
|
+
)
|
|
158
|
+
: Key extends keyof WithStringKeys<BaseType>
|
|
159
|
+
? StrictPropertyOf<WithStringKeys<BaseType>, Key, Options>
|
|
160
|
+
: unknown;
|
|
161
|
+
|
|
162
|
+
// This works by first splitting the path based on `.` and `[...]` characters into a tuple of string keys. Then it recursively uses the head key to get the next property of the current object, until there are no keys left. Number keys extract the item type from arrays, or are converted to strings to extract types from tuples and dictionaries with number keys.
|
|
163
|
+
/**
|
|
164
|
+
Get a deeply-nested property from an object using a key path, like Lodash's `.get()` function.
|
|
165
|
+
|
|
166
|
+
Use-case: Retrieve a property from deep inside an API response or some other complex object.
|
|
167
|
+
|
|
168
|
+
@example
|
|
169
|
+
```
|
|
170
|
+
import type {Get} from 'type-fest';
|
|
171
|
+
|
|
172
|
+
declare function get<BaseType, const Path extends string | readonly string[]>(object: BaseType, path: Path): Get<BaseType, Path>;
|
|
173
|
+
|
|
174
|
+
type ApiResponse = {
|
|
175
|
+
hits: {
|
|
176
|
+
hits: Array<{
|
|
177
|
+
_id: string;
|
|
178
|
+
_source: {
|
|
179
|
+
name: Array<{
|
|
180
|
+
given: string[];
|
|
181
|
+
family: string;
|
|
182
|
+
}>;
|
|
183
|
+
birthDate: string;
|
|
184
|
+
};
|
|
185
|
+
}>;
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const getName = (apiResponse: ApiResponse) => get(apiResponse, 'hits.hits[0]._source.name');
|
|
190
|
+
//=> (apiResponse: ApiResponse) => {
|
|
191
|
+
// given: string[];
|
|
192
|
+
// family: string;
|
|
193
|
+
// }[] | undefined
|
|
194
|
+
|
|
195
|
+
// Path also supports a readonly array of strings
|
|
196
|
+
const getNameWithPathArray = (apiResponse: ApiResponse) => get(apiResponse, ['hits', 'hits', '0', '_source', 'name']);
|
|
197
|
+
//=> (apiResponse: ApiResponse) => {
|
|
198
|
+
// given: string[];
|
|
199
|
+
// family: string;
|
|
200
|
+
// }[] | undefined
|
|
201
|
+
|
|
202
|
+
// Non-strict mode:
|
|
203
|
+
type A = Get<string[], '3', {strict: false}>;
|
|
204
|
+
//=> string
|
|
205
|
+
|
|
206
|
+
type B = Get<Record<string, string>, 'foo', {strict: true}>;
|
|
207
|
+
//=> string | undefined
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
@category Object
|
|
211
|
+
@category Array
|
|
212
|
+
@category Template literal
|
|
213
|
+
*/
|
|
214
|
+
export type Get<
|
|
215
|
+
BaseType,
|
|
216
|
+
Path extends
|
|
217
|
+
| readonly string[]
|
|
218
|
+
| _LiteralStringUnion<ToString<Paths<BaseType, {bracketNotation: false; maxRecursionDepth: 2}> | Paths<BaseType, {bracketNotation: true; maxRecursionDepth: 2}>>>,
|
|
219
|
+
Options extends GetOptions = {},
|
|
220
|
+
> =
|
|
221
|
+
GetWithPath<
|
|
222
|
+
BaseType,
|
|
223
|
+
Path extends string ? ToPath<Path> : Path,
|
|
224
|
+
ApplyDefaultOptions<GetOptions, DefaultGetOptions, Options>
|
|
225
|
+
>;
|
|
226
|
+
|
|
227
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Declare locally scoped properties on `globalThis`.
|
|
3
|
+
|
|
4
|
+
When defining a global variable in a declaration file is inappropriate, it can be helpful to define a `type` or `interface` (say `ExtraGlobals`) with the global variable and then cast `globalThis` via code like `globalThis as unknown as ExtraGlobals`.
|
|
5
|
+
|
|
6
|
+
Instead of casting through `unknown`, you can update your `type` or `interface` to extend `GlobalThis` and then directly cast `globalThis`.
|
|
7
|
+
|
|
8
|
+
@example
|
|
9
|
+
```
|
|
10
|
+
import type {GlobalThis} from 'type-fest';
|
|
11
|
+
|
|
12
|
+
type ExtraGlobals = GlobalThis & {
|
|
13
|
+
readonly GLOBAL_TOKEN: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const globalToken = (globalThis as ExtraGlobals).GLOBAL_TOKEN;
|
|
17
|
+
//=> string
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
@category Type
|
|
21
|
+
*/
|
|
22
|
+
export type GlobalThis = typeof globalThis;
|
|
23
|
+
|
|
24
|
+
export {};
|