@oscarpalmer/atoms 0.62.0 → 0.64.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/package.json +3 -3
- package/src/js/models.ts +2 -0
- package/src/js/value/get.ts +1 -2
- package/src/js/value/smush.ts +1 -2
- package/types/index.d.cts +1087 -9
- package/types/models.d.ts +1 -0
- package/types/value/get.d.ts +1 -2
- package/types/value/smush.d.ts +1 -2
package/package.json
CHANGED
|
@@ -175,12 +175,12 @@
|
|
|
175
175
|
"clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
|
|
176
176
|
"test": "bun test",
|
|
177
177
|
"types": "bun run types:cjs && bun run types:esm",
|
|
178
|
-
"types:cjs": "bunx dts-bundle-generator --out-file ./types/index.d.cts --no-check --silent ./src/js/index.ts",
|
|
178
|
+
"types:cjs": "bunx dts-bundle-generator --out-file ./types/index.d.cts --external-inlines 'type-fest' --no-check --silent ./src/js/index.ts",
|
|
179
179
|
"types:esm": "bunx tsc -p ./tsconfig.json",
|
|
180
180
|
"watch:css": "bunx sass ./src/css:./dist/css --no-source-map --watch",
|
|
181
181
|
"watch:js": "bun build ./src/js/index.ts --outfile ./dist/js/index.js --watch"
|
|
182
182
|
},
|
|
183
183
|
"type": "module",
|
|
184
|
-
"types": "./types/index.d.
|
|
185
|
-
"version": "0.
|
|
184
|
+
"types": "./types/index.d.cts",
|
|
185
|
+
"version": "0.64.0"
|
|
186
186
|
}
|
package/src/js/models.ts
CHANGED
|
@@ -29,6 +29,8 @@ export type Key = number | string;
|
|
|
29
29
|
|
|
30
30
|
export type PlainObject = UnknownRecord;
|
|
31
31
|
|
|
32
|
+
export type ToString<T> = T extends string | number ? `${T}` : never;
|
|
33
|
+
|
|
32
34
|
export type UnknownArrayOrRecord = UnknownArray | UnknownRecord;
|
|
33
35
|
|
|
34
36
|
export type {Get, Paths, Primitive, UnknownArray, UnknownRecord};
|
package/src/js/value/get.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type {ToString} from 'type-fest/source/internal';
|
|
2
1
|
import {handleValue} from '../internal/value-handle';
|
|
3
|
-
import type {Get, Paths, PlainObject} from '../models';
|
|
2
|
+
import type {Get, Paths, PlainObject, ToString} from '../models';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* - Get the value from an object using a known path
|
package/src/js/value/smush.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type {Get, Paths, Simplify} from 'type-fest';
|
|
2
|
-
import type {ToString} from 'type-fest/source/internal';
|
|
3
2
|
import {isArrayOrPlainObject} from '../is';
|
|
4
|
-
import type {ArrayOrPlainObject, PlainObject} from '../models';
|
|
3
|
+
import type {ArrayOrPlainObject, PlainObject, ToString} from '../models';
|
|
5
4
|
import {join} from '../string';
|
|
6
5
|
|
|
7
6
|
type Smushed<Value> = Simplify<{
|
package/types/index.d.cts
CHANGED
|
@@ -1,8 +1,1089 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
|
5
|
+
|
|
6
|
+
@category Type
|
|
7
|
+
*/
|
|
8
|
+
export type Primitive = null | undefined | string | number | boolean | symbol | bigint;
|
|
9
|
+
/**
|
|
10
|
+
Create a union of all keys from a given type, even those exclusive to specific union members.
|
|
11
|
+
|
|
12
|
+
Unlike the native `keyof` keyword, which returns keys present in **all** union members, this type returns keys from **any** member.
|
|
13
|
+
|
|
14
|
+
@link https://stackoverflow.com/a/49402091
|
|
15
|
+
|
|
16
|
+
@example
|
|
17
|
+
```
|
|
18
|
+
import type {KeysOfUnion} from 'type-fest';
|
|
19
|
+
|
|
20
|
+
type A = {
|
|
21
|
+
common: string;
|
|
22
|
+
a: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type B = {
|
|
26
|
+
common: string;
|
|
27
|
+
b: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type C = {
|
|
31
|
+
common: string;
|
|
32
|
+
c: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type Union = A | B | C;
|
|
36
|
+
|
|
37
|
+
type CommonKeys = keyof Union;
|
|
38
|
+
//=> 'common'
|
|
39
|
+
|
|
40
|
+
type AllKeys = KeysOfUnion<Union>;
|
|
41
|
+
//=> 'common' | 'a' | 'b' | 'c'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
@category Object
|
|
45
|
+
*/
|
|
46
|
+
export type KeysOfUnion<ObjectType> = ObjectType extends unknown ? keyof ObjectType : never;
|
|
47
|
+
declare const emptyObjectSymbol: unique symbol;
|
|
48
|
+
/**
|
|
49
|
+
Represents a strictly empty plain object, the `{}` value.
|
|
50
|
+
|
|
51
|
+
When you annotate something as the type `{}`, it can be anything except `null` and `undefined`. This means that you cannot use `{}` to represent an empty plain object ([read more](https://stackoverflow.com/questions/47339869/typescript-empty-object-and-any-difference/52193484#52193484)).
|
|
52
|
+
|
|
53
|
+
@example
|
|
54
|
+
```
|
|
55
|
+
import type {EmptyObject} from 'type-fest';
|
|
56
|
+
|
|
57
|
+
// The following illustrates the problem with `{}`.
|
|
58
|
+
const foo1: {} = {}; // Pass
|
|
59
|
+
const foo2: {} = []; // Pass
|
|
60
|
+
const foo3: {} = 42; // Pass
|
|
61
|
+
const foo4: {} = {a: 1}; // Pass
|
|
62
|
+
|
|
63
|
+
// With `EmptyObject` only the first case is valid.
|
|
64
|
+
const bar1: EmptyObject = {}; // Pass
|
|
65
|
+
const bar2: EmptyObject = 42; // Fail
|
|
66
|
+
const bar3: EmptyObject = []; // Fail
|
|
67
|
+
const bar4: EmptyObject = {a: 1}; // Fail
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Unfortunately, `Record<string, never>`, `Record<keyof any, never>` and `Record<never, never>` do not work. See {@link https://github.com/sindresorhus/type-fest/issues/395 #395}.
|
|
71
|
+
|
|
72
|
+
@category Object
|
|
73
|
+
*/
|
|
74
|
+
export type EmptyObject = {
|
|
75
|
+
[emptyObjectSymbol]?: never;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
Returns a boolean for whether the two given types are equal.
|
|
79
|
+
|
|
80
|
+
@link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
|
|
81
|
+
@link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796
|
|
82
|
+
|
|
83
|
+
Use-cases:
|
|
84
|
+
- If you want to make a conditional branch based on the result of a comparison of two types.
|
|
85
|
+
|
|
86
|
+
@example
|
|
87
|
+
```
|
|
88
|
+
import type {IsEqual} from 'type-fest';
|
|
89
|
+
|
|
90
|
+
// This type returns a boolean for whether the given array includes the given item.
|
|
91
|
+
// `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal.
|
|
92
|
+
type Includes<Value extends readonly any[], Item> =
|
|
93
|
+
Value extends readonly [Value[0], ...infer rest]
|
|
94
|
+
? IsEqual<Value[0], Item> extends true
|
|
95
|
+
? true
|
|
96
|
+
: Includes<rest, Item>
|
|
97
|
+
: false;
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
@category Type Guard
|
|
101
|
+
@category Utilities
|
|
102
|
+
*/
|
|
103
|
+
export type IsEqual<A, B> = (<G>() => G extends A ? 1 : 2) extends (<G>() => G extends B ? 1 : 2) ? true : false;
|
|
104
|
+
/**
|
|
105
|
+
Represents an object with `unknown` value. You probably want this instead of `{}`.
|
|
106
|
+
|
|
107
|
+
Use case: You have an object whose keys and values are unknown to you.
|
|
108
|
+
|
|
109
|
+
@example
|
|
110
|
+
```
|
|
111
|
+
import type {UnknownRecord} from 'type-fest';
|
|
112
|
+
|
|
113
|
+
function toJson(object: UnknownRecord) {
|
|
114
|
+
return JSON.stringify(object);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
toJson({hello: 'world'});
|
|
118
|
+
//=> '{"hello":"world"}'
|
|
119
|
+
|
|
120
|
+
function isObject(value: unknown): value is UnknownRecord {
|
|
121
|
+
return typeof value === 'object' && value !== null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
isObject({hello: 'world'});
|
|
125
|
+
//=> true
|
|
126
|
+
|
|
127
|
+
isObject('hello');
|
|
128
|
+
//=> false
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
@category Type
|
|
132
|
+
@category Object
|
|
133
|
+
*/
|
|
134
|
+
export type UnknownRecord = Record<PropertyKey, unknown>;
|
|
135
|
+
/**
|
|
136
|
+
Represents an array with `unknown` value.
|
|
137
|
+
|
|
138
|
+
Use case: You want a type that all arrays can be assigned to, but you don't care about the value.
|
|
139
|
+
|
|
140
|
+
@example
|
|
141
|
+
```
|
|
142
|
+
import type {UnknownArray} from 'type-fest';
|
|
143
|
+
|
|
144
|
+
type IsArray<T> = T extends UnknownArray ? true : false;
|
|
145
|
+
|
|
146
|
+
type A = IsArray<['foo']>;
|
|
147
|
+
//=> true
|
|
148
|
+
|
|
149
|
+
type B = IsArray<readonly number[]>;
|
|
150
|
+
//=> true
|
|
151
|
+
|
|
152
|
+
type C = IsArray<string>;
|
|
153
|
+
//=> false
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
@category Type
|
|
157
|
+
@category Array
|
|
158
|
+
*/
|
|
159
|
+
export type UnknownArray = readonly unknown[];
|
|
160
|
+
/**
|
|
161
|
+
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.
|
|
162
|
+
|
|
163
|
+
@example
|
|
164
|
+
```
|
|
165
|
+
import type {Simplify} from 'type-fest';
|
|
166
|
+
|
|
167
|
+
type PositionProps = {
|
|
168
|
+
top: number;
|
|
169
|
+
left: number;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
type SizeProps = {
|
|
173
|
+
width: number;
|
|
174
|
+
height: number;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// In your editor, hovering over `Props` will show a flattened object with all the properties.
|
|
178
|
+
type Props = Simplify<PositionProps & SizeProps>;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Sometimes it is desired to pass a value as a function argument that has a different type. At first inspection it may seem assignable, and then you discover it is not because the `value`'s type definition was defined as an interface. In the following example, `fn` requires an argument of type `Record<string, unknown>`. If the value is defined as a literal, then it is assignable. And if the `value` is defined as type using the `Simplify` utility the value is assignable. But if the `value` is defined as an interface, it is not assignable because the interface is not sealed and elsewhere a non-string property could be added to the interface.
|
|
182
|
+
|
|
183
|
+
If the type definition must be an interface (perhaps it was defined in a third-party npm package), then the `value` can be defined as `const value: Simplify<SomeInterface> = ...`. Then `value` will be assignable to the `fn` argument. Or the `value` can be cast as `Simplify<SomeInterface>` if you can't re-declare the `value`.
|
|
184
|
+
|
|
185
|
+
@example
|
|
186
|
+
```
|
|
187
|
+
import type {Simplify} from 'type-fest';
|
|
188
|
+
|
|
189
|
+
interface SomeInterface {
|
|
190
|
+
foo: number;
|
|
191
|
+
bar?: string;
|
|
192
|
+
baz: number | undefined;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
type SomeType = {
|
|
196
|
+
foo: number;
|
|
197
|
+
bar?: string;
|
|
198
|
+
baz: number | undefined;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const literal = {foo: 123, bar: 'hello', baz: 456};
|
|
202
|
+
const someType: SomeType = literal;
|
|
203
|
+
const someInterface: SomeInterface = literal;
|
|
204
|
+
|
|
205
|
+
function fn(object: Record<string, unknown>): void {}
|
|
206
|
+
|
|
207
|
+
fn(literal); // Good: literal object type is sealed
|
|
208
|
+
fn(someType); // Good: type is sealed
|
|
209
|
+
fn(someInterface); // Error: Index signature for type 'string' is missing in type 'someInterface'. Because `interface` can be re-opened
|
|
210
|
+
fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface` into a `type`
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
@link https://github.com/microsoft/TypeScript/issues/15300
|
|
214
|
+
@see SimplifyDeep
|
|
215
|
+
@category Object
|
|
216
|
+
*/
|
|
217
|
+
export type Simplify<T> = {
|
|
218
|
+
[KeyType in keyof T]: T[KeyType];
|
|
219
|
+
} & {};
|
|
220
|
+
/**
|
|
221
|
+
Returns the static, fixed-length portion of the given array, excluding variable-length parts.
|
|
222
|
+
|
|
223
|
+
@example
|
|
224
|
+
```
|
|
225
|
+
type A = [string, number, boolean, ...string[]];
|
|
226
|
+
type B = StaticPartOfArray<A>;
|
|
227
|
+
//=> [string, number, boolean]
|
|
228
|
+
```
|
|
229
|
+
*/
|
|
230
|
+
export type StaticPartOfArray<T extends UnknownArray, Result extends UnknownArray = [
|
|
231
|
+
]> = T extends unknown ? number extends T["length"] ? T extends readonly [
|
|
232
|
+
infer U,
|
|
233
|
+
...infer V
|
|
234
|
+
] ? StaticPartOfArray<V, [
|
|
235
|
+
...Result,
|
|
236
|
+
U
|
|
237
|
+
]> : Result : T : never; // Should never happen
|
|
238
|
+
/**
|
|
239
|
+
Returns the variable, non-fixed-length portion of the given array, excluding static-length parts.
|
|
240
|
+
|
|
241
|
+
@example
|
|
242
|
+
```
|
|
243
|
+
type A = [string, number, boolean, ...string[]];
|
|
244
|
+
type B = VariablePartOfArray<A>;
|
|
245
|
+
//=> string[]
|
|
246
|
+
```
|
|
247
|
+
*/
|
|
248
|
+
export type VariablePartOfArray<T extends UnknownArray> = T extends unknown ? T extends readonly [
|
|
249
|
+
...StaticPartOfArray<T>,
|
|
250
|
+
...infer U
|
|
251
|
+
] ? U : [
|
|
252
|
+
] : never; // Should never happen
|
|
253
|
+
export type StringDigit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
|
|
254
|
+
/**
|
|
255
|
+
Returns a boolean for whether the given type is `any`.
|
|
256
|
+
|
|
257
|
+
@link https://stackoverflow.com/a/49928360/1490091
|
|
258
|
+
|
|
259
|
+
Useful in type utilities, such as disallowing `any`s to be passed to a function.
|
|
260
|
+
|
|
261
|
+
@example
|
|
262
|
+
```
|
|
263
|
+
import type {IsAny} from 'type-fest';
|
|
264
|
+
|
|
265
|
+
const typedObject = {a: 1, b: 2} as const;
|
|
266
|
+
const anyObject: any = {a: 1, b: 2};
|
|
267
|
+
|
|
268
|
+
function get<O extends (IsAny<O> extends true ? {} : Record<string, number>), K extends keyof O = keyof O>(obj: O, key: K) {
|
|
269
|
+
return obj[key];
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const typedA = get(typedObject, 'a');
|
|
273
|
+
//=> 1
|
|
274
|
+
|
|
275
|
+
const anyA = get(anyObject, 'a');
|
|
276
|
+
//=> any
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
@category Type Guard
|
|
280
|
+
@category Utilities
|
|
281
|
+
*/
|
|
282
|
+
export type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
283
|
+
export type Numeric = number | bigint;
|
|
284
|
+
export type Zero = 0 | 0n;
|
|
285
|
+
/**
|
|
286
|
+
Matches the hidden `Infinity` type.
|
|
287
|
+
|
|
288
|
+
Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/32277) if you want to have this type as a built-in in TypeScript.
|
|
289
|
+
|
|
290
|
+
@see NegativeInfinity
|
|
291
|
+
|
|
292
|
+
@category Numeric
|
|
293
|
+
*/
|
|
294
|
+
// See https://github.com/microsoft/TypeScript/issues/31752
|
|
295
|
+
// eslint-disable-next-line @typescript-eslint/no-loss-of-precision
|
|
296
|
+
export type PositiveInfinity = Infinity;
|
|
297
|
+
/**
|
|
298
|
+
Matches the hidden `-Infinity` type.
|
|
299
|
+
|
|
300
|
+
Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/32277) if you want to have this type as a built-in in TypeScript.
|
|
301
|
+
|
|
302
|
+
@see PositiveInfinity
|
|
303
|
+
|
|
304
|
+
@category Numeric
|
|
305
|
+
*/
|
|
306
|
+
// See https://github.com/microsoft/TypeScript/issues/31752
|
|
307
|
+
// eslint-disable-next-line @typescript-eslint/no-loss-of-precision
|
|
308
|
+
export type NegativeInfinity = -Infinity;
|
|
309
|
+
/**
|
|
310
|
+
A negative `number`/`bigint` (`-∞ < x < 0`)
|
|
311
|
+
|
|
312
|
+
Use-case: Validating and documenting parameters.
|
|
313
|
+
|
|
314
|
+
@see NegativeInteger
|
|
315
|
+
@see NonNegative
|
|
316
|
+
|
|
317
|
+
@category Numeric
|
|
318
|
+
*/
|
|
319
|
+
export type Negative<T extends Numeric> = T extends Zero ? never : `${T}` extends `-${string}` ? T : never;
|
|
320
|
+
/**
|
|
321
|
+
Returns a boolean for whether the given number is a negative number.
|
|
322
|
+
|
|
323
|
+
@see Negative
|
|
324
|
+
|
|
325
|
+
@example
|
|
326
|
+
```
|
|
327
|
+
import type {IsNegative} from 'type-fest';
|
|
328
|
+
|
|
329
|
+
type ShouldBeFalse = IsNegative<1>;
|
|
330
|
+
type ShouldBeTrue = IsNegative<-1>;
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
@category Numeric
|
|
334
|
+
*/
|
|
335
|
+
export type IsNegative<T extends Numeric> = T extends Negative<T> ? true : false;
|
|
336
|
+
/**
|
|
337
|
+
Returns a boolean for whether the given type is `never`.
|
|
338
|
+
|
|
339
|
+
@link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
|
|
340
|
+
@link https://stackoverflow.com/a/53984913/10292952
|
|
341
|
+
@link https://www.zhenghao.io/posts/ts-never
|
|
342
|
+
|
|
343
|
+
Useful in type utilities, such as checking if something does not occur.
|
|
344
|
+
|
|
345
|
+
@example
|
|
346
|
+
```
|
|
347
|
+
import type {IsNever, And} from 'type-fest';
|
|
348
|
+
|
|
349
|
+
// https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts
|
|
350
|
+
type AreStringsEqual<A extends string, B extends string> =
|
|
351
|
+
And<
|
|
352
|
+
IsNever<Exclude<A, B>> extends true ? true : false,
|
|
353
|
+
IsNever<Exclude<B, A>> extends true ? true : false
|
|
354
|
+
>;
|
|
355
|
+
|
|
356
|
+
type EndIfEqual<I extends string, O extends string> =
|
|
357
|
+
AreStringsEqual<I, O> extends true
|
|
358
|
+
? never
|
|
359
|
+
: void;
|
|
360
|
+
|
|
361
|
+
function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> {
|
|
362
|
+
if (input === output) {
|
|
363
|
+
process.exit(0);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
endIfEqual('abc', 'abc');
|
|
368
|
+
//=> never
|
|
369
|
+
|
|
370
|
+
endIfEqual('abc', '123');
|
|
371
|
+
//=> void
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
@category Type Guard
|
|
375
|
+
@category Utilities
|
|
376
|
+
*/
|
|
377
|
+
export type IsNever<T> = [
|
|
378
|
+
T
|
|
379
|
+
] extends [
|
|
380
|
+
never
|
|
381
|
+
] ? true : false;
|
|
382
|
+
/**
|
|
383
|
+
Returns a boolean for whether two given types are both true.
|
|
384
|
+
|
|
385
|
+
Use-case: Constructing complex conditional types where multiple conditions must be satisfied.
|
|
386
|
+
|
|
387
|
+
@example
|
|
388
|
+
```
|
|
389
|
+
import type {And} from 'type-fest';
|
|
390
|
+
|
|
391
|
+
And<true, true>;
|
|
392
|
+
//=> true
|
|
393
|
+
|
|
394
|
+
And<true, false>;
|
|
395
|
+
//=> false
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
@see {@link Or}
|
|
399
|
+
*/
|
|
400
|
+
export type And<A extends boolean, B extends boolean> = [
|
|
401
|
+
A,
|
|
402
|
+
B
|
|
403
|
+
][number] extends true ? true : true extends [
|
|
404
|
+
IsEqual<A, false>,
|
|
405
|
+
IsEqual<B, false>
|
|
406
|
+
][number] ? false : never;
|
|
407
|
+
/**
|
|
408
|
+
Returns a boolean for whether either of two given types are true.
|
|
409
|
+
|
|
410
|
+
Use-case: Constructing complex conditional types where multiple conditions must be satisfied.
|
|
411
|
+
|
|
412
|
+
@example
|
|
413
|
+
```
|
|
414
|
+
import type {Or} from 'type-fest';
|
|
415
|
+
|
|
416
|
+
Or<true, false>;
|
|
417
|
+
//=> true
|
|
418
|
+
|
|
419
|
+
Or<false, false>;
|
|
420
|
+
//=> false
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
@see {@link And}
|
|
424
|
+
*/
|
|
425
|
+
export type Or<A extends boolean, B extends boolean> = [
|
|
426
|
+
A,
|
|
427
|
+
B
|
|
428
|
+
][number] extends false ? false : true extends [
|
|
429
|
+
IsEqual<A, true>,
|
|
430
|
+
IsEqual<B, true>
|
|
431
|
+
][number] ? true : never;
|
|
432
|
+
/**
|
|
433
|
+
Returns a boolean for whether a given number is greater than another number.
|
|
434
|
+
|
|
435
|
+
@example
|
|
436
|
+
```
|
|
437
|
+
import type {GreaterThan} from 'type-fest';
|
|
438
|
+
|
|
439
|
+
GreaterThan<1, -5>;
|
|
440
|
+
//=> true
|
|
441
|
+
|
|
442
|
+
GreaterThan<1, 1>;
|
|
443
|
+
//=> false
|
|
444
|
+
|
|
445
|
+
GreaterThan<1, 5>;
|
|
446
|
+
//=> false
|
|
447
|
+
```
|
|
448
|
+
*/
|
|
449
|
+
export type GreaterThan<A extends number, B extends number> = number extends A | B ? never : [
|
|
450
|
+
IsEqual<A, PositiveInfinity>,
|
|
451
|
+
IsEqual<A, NegativeInfinity>,
|
|
452
|
+
IsEqual<B, PositiveInfinity>,
|
|
453
|
+
IsEqual<B, NegativeInfinity>
|
|
454
|
+
] extends infer R extends [
|
|
455
|
+
boolean,
|
|
456
|
+
boolean,
|
|
457
|
+
boolean,
|
|
458
|
+
boolean
|
|
459
|
+
] ? Or<And<IsEqual<R[0], true>, IsEqual<R[2], false>>, And<IsEqual<R[3], true>, IsEqual<R[1], false>>> extends true ? true : Or<And<IsEqual<R[1], true>, IsEqual<R[3], false>>, And<IsEqual<R[2], true>, IsEqual<R[0], false>>> extends true ? false : true extends R[number] ? false : [
|
|
460
|
+
IsNegative<A>,
|
|
461
|
+
IsNegative<B>
|
|
462
|
+
] extends infer R extends [
|
|
463
|
+
boolean,
|
|
464
|
+
boolean
|
|
465
|
+
] ? [
|
|
466
|
+
true,
|
|
467
|
+
false
|
|
468
|
+
] extends R ? false : [
|
|
469
|
+
false,
|
|
470
|
+
true
|
|
471
|
+
] extends R ? true : [
|
|
472
|
+
false,
|
|
473
|
+
false
|
|
474
|
+
] extends R ? PositiveNumericStringGt<`${A}`, `${B}`> : PositiveNumericStringGt<`${NumberAbsolute<B>}`, `${NumberAbsolute<A>}`> : never : never;
|
|
475
|
+
/**
|
|
476
|
+
Returns a boolean for whether a given number is greater than or equal to another number.
|
|
477
|
+
|
|
478
|
+
@example
|
|
479
|
+
```
|
|
480
|
+
import type {GreaterThanOrEqual} from 'type-fest';
|
|
481
|
+
|
|
482
|
+
GreaterThanOrEqual<1, -5>;
|
|
483
|
+
//=> true
|
|
484
|
+
|
|
485
|
+
GreaterThanOrEqual<1, 1>;
|
|
486
|
+
//=> true
|
|
487
|
+
|
|
488
|
+
GreaterThanOrEqual<1, 5>;
|
|
489
|
+
//=> false
|
|
490
|
+
```
|
|
491
|
+
*/
|
|
492
|
+
export type GreaterThanOrEqual<A extends number, B extends number> = number extends A | B ? never : A extends B ? true : GreaterThan<A, B>;
|
|
493
|
+
/**
|
|
494
|
+
Returns a boolean for whether a given number is less than another number.
|
|
495
|
+
|
|
496
|
+
@example
|
|
497
|
+
```
|
|
498
|
+
import type {LessThan} from 'type-fest';
|
|
499
|
+
|
|
500
|
+
LessThan<1, -5>;
|
|
501
|
+
//=> false
|
|
502
|
+
|
|
503
|
+
LessThan<1, 1>;
|
|
504
|
+
//=> false
|
|
505
|
+
|
|
506
|
+
LessThan<1, 5>;
|
|
507
|
+
//=> true
|
|
508
|
+
```
|
|
509
|
+
*/
|
|
510
|
+
export type LessThan<A extends number, B extends number> = number extends A | B ? never : GreaterThanOrEqual<A, B> extends true ? false : true;
|
|
511
|
+
/**
|
|
512
|
+
Create a tuple type of the given length `<L>` and fill it with the given type `<Fill>`.
|
|
513
|
+
|
|
514
|
+
If `<Fill>` is not provided, it will default to `unknown`.
|
|
515
|
+
|
|
516
|
+
@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
|
|
517
|
+
*/
|
|
518
|
+
export type BuildTuple<L extends number, Fill = unknown, T extends readonly unknown[] = [
|
|
519
|
+
]> = T["length"] extends L ? T : BuildTuple<L, Fill, [
|
|
520
|
+
...T,
|
|
521
|
+
Fill
|
|
522
|
+
]>;
|
|
523
|
+
/**
|
|
524
|
+
Returns the maximum value from a tuple of integers.
|
|
525
|
+
|
|
526
|
+
Note:
|
|
527
|
+
- Float numbers are not supported.
|
|
528
|
+
|
|
529
|
+
@example
|
|
530
|
+
```
|
|
531
|
+
ArrayMax<[1, 2, 5, 3]>;
|
|
532
|
+
//=> 5
|
|
533
|
+
|
|
534
|
+
ArrayMax<[1, 2, 5, 3, 99, -1]>;
|
|
535
|
+
//=> 99
|
|
536
|
+
```
|
|
537
|
+
*/
|
|
538
|
+
export type TupleMax<A extends number[], Result extends number = NegativeInfinity> = number extends A[number] ? never : A extends [
|
|
539
|
+
infer F extends number,
|
|
540
|
+
...infer R extends number[]
|
|
541
|
+
] ? GreaterThan<F, Result> extends true ? TupleMax<R, F> : TupleMax<R, Result> : Result;
|
|
542
|
+
/**
|
|
543
|
+
Returns the minimum value from a tuple of integers.
|
|
544
|
+
|
|
545
|
+
Note:
|
|
546
|
+
- Float numbers are not supported.
|
|
547
|
+
|
|
548
|
+
@example
|
|
549
|
+
```
|
|
550
|
+
ArrayMin<[1, 2, 5, 3]>;
|
|
551
|
+
//=> 1
|
|
552
|
+
|
|
553
|
+
ArrayMin<[1, 2, 5, 3, -5]>;
|
|
554
|
+
//=> -5
|
|
555
|
+
```
|
|
556
|
+
*/
|
|
557
|
+
export type TupleMin<A extends number[], Result extends number = PositiveInfinity> = number extends A[number] ? never : A extends [
|
|
558
|
+
infer F extends number,
|
|
559
|
+
...infer R extends number[]
|
|
560
|
+
] ? LessThan<F, Result> extends true ? TupleMin<R, F> : TupleMin<R, Result> : Result;
|
|
561
|
+
/**
|
|
562
|
+
Return a string representation of the given string or number.
|
|
563
|
+
|
|
564
|
+
Note: This type is not the return type of the `.toString()` function.
|
|
565
|
+
*/
|
|
566
|
+
export type ToString<T> = T extends string | number ? `${T}` : never;
|
|
567
|
+
/**
|
|
568
|
+
Converts a numeric string to a number.
|
|
569
|
+
|
|
570
|
+
@example
|
|
571
|
+
```
|
|
572
|
+
type PositiveInt = StringToNumber<'1234'>;
|
|
573
|
+
//=> 1234
|
|
574
|
+
|
|
575
|
+
type NegativeInt = StringToNumber<'-1234'>;
|
|
576
|
+
//=> -1234
|
|
577
|
+
|
|
578
|
+
type PositiveFloat = StringToNumber<'1234.56'>;
|
|
579
|
+
//=> 1234.56
|
|
580
|
+
|
|
581
|
+
type NegativeFloat = StringToNumber<'-1234.56'>;
|
|
582
|
+
//=> -1234.56
|
|
583
|
+
|
|
584
|
+
type PositiveInfinity = StringToNumber<'Infinity'>;
|
|
585
|
+
//=> Infinity
|
|
586
|
+
|
|
587
|
+
type NegativeInfinity = StringToNumber<'-Infinity'>;
|
|
588
|
+
//=> -Infinity
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
@category String
|
|
592
|
+
@category Numeric
|
|
593
|
+
@category Template literal
|
|
594
|
+
*/
|
|
595
|
+
export type StringToNumber<S extends string> = S extends `${infer N extends number}` ? N : S extends "Infinity" ? PositiveInfinity : S extends "-Infinity" ? NegativeInfinity : never;
|
|
596
|
+
/**
|
|
597
|
+
Returns an array of the characters of the string.
|
|
598
|
+
|
|
599
|
+
@example
|
|
600
|
+
```
|
|
601
|
+
StringToArray<'abcde'>;
|
|
602
|
+
//=> ['a', 'b', 'c', 'd', 'e']
|
|
603
|
+
|
|
604
|
+
StringToArray<string>;
|
|
605
|
+
//=> never
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
@category String
|
|
609
|
+
*/
|
|
610
|
+
export type StringToArray<S extends string, Result extends string[] = [
|
|
611
|
+
]> = string extends S ? never : S extends `${infer F}${infer R}` ? StringToArray<R, [
|
|
612
|
+
...Result,
|
|
613
|
+
F
|
|
614
|
+
]> : Result;
|
|
615
|
+
/**
|
|
616
|
+
Returns the length of the given string.
|
|
617
|
+
|
|
618
|
+
@example
|
|
619
|
+
```
|
|
620
|
+
StringLength<'abcde'>;
|
|
621
|
+
//=> 5
|
|
622
|
+
|
|
623
|
+
StringLength<string>;
|
|
624
|
+
//=> never
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
@category String
|
|
628
|
+
@category Template literal
|
|
629
|
+
*/
|
|
630
|
+
export type StringLength<S extends string> = string extends S ? never : StringToArray<S>["length"];
|
|
631
|
+
/**
|
|
632
|
+
Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both numeric strings and have the same length.
|
|
633
|
+
|
|
634
|
+
@example
|
|
635
|
+
```
|
|
636
|
+
SameLengthPositiveNumericStringGt<'50', '10'>;
|
|
637
|
+
//=> true
|
|
638
|
+
|
|
639
|
+
SameLengthPositiveNumericStringGt<'10', '10'>;
|
|
640
|
+
//=> false
|
|
641
|
+
```
|
|
642
|
+
*/
|
|
643
|
+
export type SameLengthPositiveNumericStringGt<A extends string, B extends string> = A extends `${infer FirstA}${infer RestA}` ? B extends `${infer FirstB}${infer RestB}` ? FirstA extends FirstB ? SameLengthPositiveNumericStringGt<RestA, RestB> : PositiveNumericCharacterGt<FirstA, FirstB> : never : false;
|
|
644
|
+
export type NumericString = "0123456789";
|
|
645
|
+
/**
|
|
646
|
+
Returns a boolean for whether `A` is greater than `B`, where `A` and `B` are both positive numeric strings.
|
|
647
|
+
|
|
648
|
+
@example
|
|
649
|
+
```
|
|
650
|
+
PositiveNumericStringGt<'500', '1'>;
|
|
651
|
+
//=> true
|
|
652
|
+
|
|
653
|
+
PositiveNumericStringGt<'1', '1'>;
|
|
654
|
+
//=> false
|
|
655
|
+
|
|
656
|
+
PositiveNumericStringGt<'1', '500'>;
|
|
657
|
+
//=> false
|
|
658
|
+
```
|
|
659
|
+
*/
|
|
660
|
+
export type PositiveNumericStringGt<A extends string, B extends string> = A extends B ? false : [
|
|
661
|
+
BuildTuple<StringLength<A>, 0>,
|
|
662
|
+
BuildTuple<StringLength<B>, 0>
|
|
663
|
+
] extends infer R extends [
|
|
664
|
+
readonly unknown[],
|
|
665
|
+
readonly unknown[]
|
|
666
|
+
] ? R[0] extends [
|
|
667
|
+
...R[1],
|
|
668
|
+
...infer Remain extends readonly unknown[]
|
|
669
|
+
] ? 0 extends Remain["length"] ? SameLengthPositiveNumericStringGt<A, B> : true : false : never;
|
|
670
|
+
/**
|
|
671
|
+
Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both positive numeric characters.
|
|
672
|
+
|
|
673
|
+
@example
|
|
674
|
+
```
|
|
675
|
+
PositiveNumericCharacterGt<'5', '1'>;
|
|
676
|
+
//=> true
|
|
677
|
+
|
|
678
|
+
PositiveNumericCharacterGt<'1', '1'>;
|
|
679
|
+
//=> false
|
|
680
|
+
```
|
|
681
|
+
*/
|
|
682
|
+
export type PositiveNumericCharacterGt<A extends string, B extends string> = NumericString extends `${infer HeadA}${A}${infer TailA}` ? NumericString extends `${infer HeadB}${B}${infer TailB}` ? HeadA extends `${HeadB}${infer _}${infer __}` ? true : false : never : never;
|
|
683
|
+
/**
|
|
684
|
+
Returns the absolute value of a given value.
|
|
685
|
+
|
|
686
|
+
@example
|
|
687
|
+
```
|
|
688
|
+
NumberAbsolute<-1>;
|
|
689
|
+
//=> 1
|
|
690
|
+
|
|
691
|
+
NumberAbsolute<1>;
|
|
692
|
+
//=> 1
|
|
693
|
+
|
|
694
|
+
NumberAbsolute<NegativeInfinity>
|
|
695
|
+
//=> PositiveInfinity
|
|
696
|
+
```
|
|
697
|
+
*/
|
|
698
|
+
export type NumberAbsolute<N extends number> = `${N}` extends `-${infer StringPositiveN}` ? StringToNumber<StringPositiveN> : N;
|
|
699
|
+
/**
|
|
700
|
+
Matches any primitive, `void`, `Date`, or `RegExp` value.
|
|
701
|
+
*/
|
|
702
|
+
export type BuiltIns = Primitive | void | Date | RegExp;
|
|
703
|
+
/**
|
|
704
|
+
Matches non-recursive types.
|
|
705
|
+
*/
|
|
706
|
+
export type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
|
|
707
|
+
/**
|
|
708
|
+
Returns the sum of two numbers.
|
|
709
|
+
|
|
710
|
+
Note:
|
|
711
|
+
- A or B can only support `-999` ~ `999`.
|
|
712
|
+
- A and B can only be small integers, less than 1000.
|
|
713
|
+
- If the result is negative, you can only get `number`.
|
|
714
|
+
|
|
715
|
+
@example
|
|
716
|
+
```
|
|
717
|
+
import type {Sum} from 'type-fest';
|
|
718
|
+
|
|
719
|
+
Sum<111, 222>;
|
|
720
|
+
//=> 333
|
|
721
|
+
|
|
722
|
+
Sum<-111, 222>;
|
|
723
|
+
//=> 111
|
|
724
|
+
|
|
725
|
+
Sum<111, -222>;
|
|
726
|
+
//=> number
|
|
727
|
+
|
|
728
|
+
Sum<PositiveInfinity, -9999>;
|
|
729
|
+
//=> PositiveInfinity
|
|
730
|
+
|
|
731
|
+
Sum<PositiveInfinity, NegativeInfinity>;
|
|
732
|
+
//=> number
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
@category Numeric
|
|
736
|
+
*/
|
|
737
|
+
// TODO: Support big integer and negative number.
|
|
738
|
+
export type Sum<A extends number, B extends number> = number extends A | B ? number : [
|
|
739
|
+
IsEqual<A, PositiveInfinity>,
|
|
740
|
+
IsEqual<A, NegativeInfinity>,
|
|
741
|
+
IsEqual<B, PositiveInfinity>,
|
|
742
|
+
IsEqual<B, NegativeInfinity>
|
|
743
|
+
] extends infer R extends [
|
|
744
|
+
boolean,
|
|
745
|
+
boolean,
|
|
746
|
+
boolean,
|
|
747
|
+
boolean
|
|
748
|
+
] ? Or<And<IsEqual<R[0], true>, IsEqual<R[3], false>>, And<IsEqual<R[2], true>, IsEqual<R[1], false>>> extends true ? PositiveInfinity : Or<And<IsEqual<R[1], true>, IsEqual<R[2], false>>, And<IsEqual<R[3], true>, IsEqual<R[0], false>>> extends true ? NegativeInfinity : true extends R[number] ? number : ([
|
|
749
|
+
IsNegative<A>,
|
|
750
|
+
IsNegative<B>
|
|
751
|
+
] extends infer R ? [
|
|
752
|
+
false,
|
|
753
|
+
false
|
|
754
|
+
] extends R ? [
|
|
755
|
+
...BuildTuple<A>,
|
|
756
|
+
...BuildTuple<B>
|
|
757
|
+
]["length"] : [
|
|
758
|
+
true,
|
|
759
|
+
true
|
|
760
|
+
] extends R ? number : TupleMax<[
|
|
761
|
+
NumberAbsolute<A>,
|
|
762
|
+
NumberAbsolute<B>
|
|
763
|
+
]> extends infer Max_ ? TupleMin<[
|
|
764
|
+
NumberAbsolute<A>,
|
|
765
|
+
NumberAbsolute<B>
|
|
766
|
+
]> extends infer Min_ extends number ? Max_ extends A | B ? Subtract<Max_, Min_> : number : never : never : never) & number : never;
|
|
767
|
+
/**
|
|
768
|
+
Returns the difference between two numbers.
|
|
769
|
+
|
|
770
|
+
Note:
|
|
771
|
+
- A or B can only support `-999` ~ `999`.
|
|
772
|
+
- If the result is negative, you can only get `number`.
|
|
773
|
+
|
|
774
|
+
@example
|
|
775
|
+
```
|
|
776
|
+
import type {Subtract} from 'type-fest';
|
|
777
|
+
|
|
778
|
+
Subtract<333, 222>;
|
|
779
|
+
//=> 111
|
|
780
|
+
|
|
781
|
+
Subtract<111, -222>;
|
|
782
|
+
//=> 333
|
|
783
|
+
|
|
784
|
+
Subtract<-111, 222>;
|
|
785
|
+
//=> number
|
|
786
|
+
|
|
787
|
+
Subtract<PositiveInfinity, 9999>;
|
|
788
|
+
//=> PositiveInfinity
|
|
789
|
+
|
|
790
|
+
Subtract<PositiveInfinity, PositiveInfinity>;
|
|
791
|
+
//=> number
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
@category Numeric
|
|
795
|
+
*/
|
|
796
|
+
// TODO: Support big integer and negative number.
|
|
797
|
+
export type Subtract<A extends number, B extends number> = number extends A | B ? number : [
|
|
798
|
+
IsEqual<A, PositiveInfinity>,
|
|
799
|
+
IsEqual<A, NegativeInfinity>,
|
|
800
|
+
IsEqual<B, PositiveInfinity>,
|
|
801
|
+
IsEqual<B, NegativeInfinity>
|
|
802
|
+
] extends infer R extends [
|
|
803
|
+
boolean,
|
|
804
|
+
boolean,
|
|
805
|
+
boolean,
|
|
806
|
+
boolean
|
|
807
|
+
] ? Or<And<IsEqual<R[0], true>, IsEqual<R[2], false>>, And<IsEqual<R[3], true>, IsEqual<R[1], false>>> extends true ? PositiveInfinity : Or<And<IsEqual<R[1], true>, IsEqual<R[3], false>>, And<IsEqual<R[2], true>, IsEqual<R[0], false>>> extends true ? NegativeInfinity : true extends R[number] ? number : [
|
|
808
|
+
IsNegative<A>,
|
|
809
|
+
IsNegative<B>
|
|
810
|
+
] extends infer R ? [
|
|
811
|
+
false,
|
|
812
|
+
false
|
|
813
|
+
] extends R ? BuildTuple<A> extends infer R ? R extends [
|
|
814
|
+
...BuildTuple<B>,
|
|
815
|
+
...infer R
|
|
816
|
+
] ? R["length"] : number : never : LessThan<A, B> extends true ? number : [
|
|
817
|
+
false,
|
|
818
|
+
true
|
|
819
|
+
] extends R ? Sum<A, NumberAbsolute<B>> : Subtract<NumberAbsolute<B>, NumberAbsolute<A>> : never : never;
|
|
820
|
+
/**
|
|
821
|
+
Paths options.
|
|
822
|
+
|
|
823
|
+
@see {@link Paths}
|
|
824
|
+
*/
|
|
825
|
+
export type PathsOptions = {
|
|
826
|
+
/**
|
|
827
|
+
The maximum depth to recurse when searching for paths.
|
|
828
|
+
|
|
829
|
+
@default 10
|
|
830
|
+
*/
|
|
831
|
+
maxRecursionDepth?: number;
|
|
832
|
+
};
|
|
833
|
+
/**
|
|
834
|
+
Generate a union of all possible paths to properties in the given object.
|
|
835
|
+
|
|
836
|
+
It also works with arrays.
|
|
837
|
+
|
|
838
|
+
Use-case: You want a type-safe way to access deeply nested properties in an object.
|
|
839
|
+
|
|
840
|
+
@example
|
|
841
|
+
```
|
|
842
|
+
import type {Paths} from 'type-fest';
|
|
843
|
+
|
|
844
|
+
type Project = {
|
|
845
|
+
filename: string;
|
|
846
|
+
listA: string[];
|
|
847
|
+
listB: [{filename: string}];
|
|
848
|
+
folder: {
|
|
849
|
+
subfolder: {
|
|
850
|
+
filename: string;
|
|
851
|
+
};
|
|
852
|
+
};
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
type ProjectPaths = Paths<Project>;
|
|
856
|
+
//=> 'filename' | 'listA' | 'listB' | 'folder' | `listA.${number}` | 'listB.0' | 'listB.0.filename' | 'folder.subfolder' | 'folder.subfolder.filename'
|
|
857
|
+
|
|
858
|
+
declare function open<Path extends ProjectPaths>(path: Path): void;
|
|
859
|
+
|
|
860
|
+
open('filename'); // Pass
|
|
861
|
+
open('folder.subfolder'); // Pass
|
|
862
|
+
open('folder.subfolder.filename'); // Pass
|
|
863
|
+
open('foo'); // TypeError
|
|
864
|
+
|
|
865
|
+
// Also works with arrays
|
|
866
|
+
open('listA.1'); // Pass
|
|
867
|
+
open('listB.0'); // Pass
|
|
868
|
+
open('listB.1'); // TypeError. Because listB only has one element.
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
@category Object
|
|
872
|
+
@category Array
|
|
873
|
+
*/
|
|
874
|
+
export type Paths<T, Options extends PathsOptions = {}> = T extends NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> ? never : IsAny<T> extends true ? never : T extends UnknownArray ? number extends T["length"] ? InternalPaths<StaticPartOfArray<T>, Options> | InternalPaths<Array<VariablePartOfArray<T>[number]>, Options> : InternalPaths<T, Options> : T extends object ? InternalPaths<T, Options> : never;
|
|
875
|
+
export type InternalPaths<T, Options extends PathsOptions = {}> = (Options["maxRecursionDepth"] extends number ? Options["maxRecursionDepth"] : 10) extends infer MaxDepth extends number ? Required<T> extends infer T ? T extends EmptyObject | readonly [
|
|
876
|
+
] ? never : {
|
|
877
|
+
[Key in keyof T]: Key extends string | number // Limit `Key` to string or number.
|
|
878
|
+
? Key | ToString<Key> | (GreaterThan<MaxDepth, 0> extends true // Limit the depth to prevent infinite recursion
|
|
879
|
+
? IsNever<Paths<T[Key], {
|
|
880
|
+
maxRecursionDepth: Subtract<MaxDepth, 1>;
|
|
881
|
+
}>> extends false ? `${Key}.${Paths<T[Key], {
|
|
882
|
+
maxRecursionDepth: Subtract<MaxDepth, 1>;
|
|
883
|
+
}>}` : never : never) : never;
|
|
884
|
+
}[keyof T & (T extends UnknownArray ? number : unknown)] : never : never;
|
|
885
|
+
/**
|
|
886
|
+
Get keys of the given type as strings.
|
|
887
|
+
|
|
888
|
+
Number keys are converted to strings.
|
|
889
|
+
|
|
890
|
+
Use-cases:
|
|
891
|
+
- Get string keys from a type which may have number keys.
|
|
892
|
+
- Makes it possible to index using strings retrieved from template types.
|
|
893
|
+
|
|
894
|
+
@example
|
|
895
|
+
```
|
|
896
|
+
import type {StringKeyOf} from 'type-fest';
|
|
897
|
+
|
|
898
|
+
type Foo = {
|
|
899
|
+
1: number,
|
|
900
|
+
stringKey: string,
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
type StringKeysOfFoo = StringKeyOf<Foo>;
|
|
904
|
+
//=> '1' | 'stringKey'
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
@category Object
|
|
908
|
+
*/
|
|
909
|
+
export type StringKeyOf<BaseType> = `${Extract<keyof BaseType, string | number>}`;
|
|
910
|
+
/**
|
|
911
|
+
Represents an array of strings split using a given character or character set.
|
|
912
|
+
|
|
913
|
+
Use-case: Defining the return type of a method like `String.prototype.split`.
|
|
914
|
+
|
|
915
|
+
@example
|
|
916
|
+
```
|
|
917
|
+
import type {Split} from 'type-fest';
|
|
918
|
+
|
|
919
|
+
declare function split<S extends string, D extends string>(string: S, separator: D): Split<S, D>;
|
|
920
|
+
|
|
921
|
+
type Item = 'foo' | 'bar' | 'baz' | 'waldo';
|
|
922
|
+
const items = 'foo,bar,baz,waldo';
|
|
923
|
+
let array: Item[];
|
|
924
|
+
|
|
925
|
+
array = split(items, ',');
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
@category String
|
|
929
|
+
@category Template literal
|
|
930
|
+
*/
|
|
931
|
+
export type Split<S extends string, Delimiter extends string> = S extends `${infer Head}${Delimiter}${infer Tail}` ? [
|
|
932
|
+
Head,
|
|
933
|
+
...Split<Tail, Delimiter>
|
|
934
|
+
] : S extends Delimiter ? [
|
|
935
|
+
] : [
|
|
936
|
+
S
|
|
937
|
+
];
|
|
938
|
+
export type GetOptions = {
|
|
939
|
+
/**
|
|
940
|
+
Include `undefined` in the return type when accessing properties.
|
|
941
|
+
|
|
942
|
+
Setting this to `false` is not recommended.
|
|
943
|
+
|
|
944
|
+
@default true
|
|
945
|
+
*/
|
|
946
|
+
strict?: boolean;
|
|
947
|
+
};
|
|
948
|
+
/**
|
|
949
|
+
Like the `Get` type but receives an array of strings as a path parameter.
|
|
950
|
+
*/
|
|
951
|
+
export type GetWithPath<BaseType, Keys extends readonly string[], Options extends GetOptions = {}> = Keys extends readonly [
|
|
952
|
+
] ? BaseType : Keys extends readonly [
|
|
953
|
+
infer Head,
|
|
954
|
+
...infer Tail
|
|
955
|
+
] ? GetWithPath<PropertyOf<BaseType, Extract<Head, string>, Options>, Extract<Tail, string[]>, Options> : never;
|
|
956
|
+
/**
|
|
957
|
+
Adds `undefined` to `Type` if `strict` is enabled.
|
|
958
|
+
*/
|
|
959
|
+
export type Strictify<Type, Options extends GetOptions> = Options["strict"] extends false ? Type : (Type | undefined);
|
|
960
|
+
/**
|
|
961
|
+
If `Options['strict']` is `true`, includes `undefined` in the returned type when accessing properties on `Record<string, any>`.
|
|
962
|
+
|
|
963
|
+
Known limitations:
|
|
964
|
+
- Does not include `undefined` in the type on object types with an index signature (for example, `{a: string; [key: string]: string}`).
|
|
965
|
+
*/
|
|
966
|
+
export type StrictPropertyOf<BaseType, Key extends keyof BaseType, Options extends GetOptions> = Record<string, any> extends BaseType ? string extends keyof BaseType ? Strictify<BaseType[Key], Options> // Record<string, any>
|
|
967
|
+
: BaseType[Key] // Record<'a' | 'b', any> (Records with a string union as keys have required properties)
|
|
968
|
+
: BaseType[Key];
|
|
969
|
+
/**
|
|
970
|
+
Splits a dot-prop style path into a tuple comprised of the properties in the path. Handles square-bracket notation.
|
|
971
|
+
|
|
972
|
+
@example
|
|
973
|
+
```
|
|
974
|
+
ToPath<'foo.bar.baz'>
|
|
975
|
+
//=> ['foo', 'bar', 'baz']
|
|
976
|
+
|
|
977
|
+
ToPath<'foo[0].bar.baz'>
|
|
978
|
+
//=> ['foo', '0', 'bar', 'baz']
|
|
979
|
+
```
|
|
980
|
+
*/
|
|
981
|
+
export type ToPath<S extends string> = Split<FixPathSquareBrackets<S>, ".">;
|
|
982
|
+
/**
|
|
983
|
+
Replaces square-bracketed dot notation with dots, for example, `foo[0].bar` -> `foo.0.bar`.
|
|
984
|
+
*/
|
|
985
|
+
export type FixPathSquareBrackets<Path extends string> = Path extends `[${infer Head}]${infer Tail}` ? Tail extends `[${string}` ? `${Head}.${FixPathSquareBrackets<Tail>}` : `${Head}${FixPathSquareBrackets<Tail>}` : Path extends `${infer Head}[${infer Middle}]${infer Tail}` ? `${Head}.${FixPathSquareBrackets<`[${Middle}]${Tail}`>}` : Path;
|
|
986
|
+
/**
|
|
987
|
+
Returns true if `LongString` is made up out of `Substring` repeated 0 or more times.
|
|
988
|
+
|
|
989
|
+
@example
|
|
990
|
+
```
|
|
991
|
+
ConsistsOnlyOf<'aaa', 'a'> //=> true
|
|
992
|
+
ConsistsOnlyOf<'ababab', 'ab'> //=> true
|
|
993
|
+
ConsistsOnlyOf<'aBa', 'a'> //=> false
|
|
994
|
+
ConsistsOnlyOf<'', 'a'> //=> true
|
|
995
|
+
```
|
|
996
|
+
*/
|
|
997
|
+
export type ConsistsOnlyOf<LongString extends string, Substring extends string> = LongString extends "" ? true : LongString extends `${Substring}${infer Tail}` ? ConsistsOnlyOf<Tail, Substring> : false;
|
|
998
|
+
/**
|
|
999
|
+
Convert a type which may have number keys to one with string keys, making it possible to index using strings retrieved from template types.
|
|
1000
|
+
|
|
1001
|
+
@example
|
|
1002
|
+
```
|
|
1003
|
+
type WithNumbers = {foo: string; 0: boolean};
|
|
1004
|
+
type WithStrings = WithStringKeys<WithNumbers>;
|
|
1005
|
+
|
|
1006
|
+
type WithNumbersKeys = keyof WithNumbers;
|
|
1007
|
+
//=> 'foo' | 0
|
|
1008
|
+
type WithStringsKeys = keyof WithStrings;
|
|
1009
|
+
//=> 'foo' | '0'
|
|
1010
|
+
```
|
|
1011
|
+
*/
|
|
1012
|
+
export type WithStringKeys<BaseType> = {
|
|
1013
|
+
[Key in StringKeyOf<BaseType>]: UncheckedIndex<BaseType, Key>;
|
|
1014
|
+
};
|
|
1015
|
+
/**
|
|
1016
|
+
Perform a `T[U]` operation if `T` supports indexing.
|
|
1017
|
+
*/
|
|
1018
|
+
export type UncheckedIndex<T, U extends string | number> = [
|
|
1019
|
+
T
|
|
1020
|
+
] extends [
|
|
1021
|
+
Record<string | number, any>
|
|
1022
|
+
] ? T[U] : never;
|
|
1023
|
+
/**
|
|
1024
|
+
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.
|
|
1025
|
+
|
|
1026
|
+
Note:
|
|
1027
|
+
- 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.
|
|
1028
|
+
- Returns `undefined` from nullish values, to match the behaviour of most deep-key libraries like `lodash`, `dot-prop`, etc.
|
|
1029
|
+
*/
|
|
1030
|
+
export type PropertyOf<BaseType, Key extends string, Options extends GetOptions = {}> = BaseType extends null | undefined ? undefined : Key extends keyof BaseType ? StrictPropertyOf<BaseType, Key, Options> : BaseType extends readonly [
|
|
1031
|
+
] | readonly [
|
|
1032
|
+
unknown,
|
|
1033
|
+
...unknown[]
|
|
1034
|
+
] ? unknown // It's a tuple, but `Key` did not extend `keyof BaseType`. So the index is out of bounds.
|
|
1035
|
+
: BaseType extends {
|
|
1036
|
+
[n: number]: infer Item;
|
|
1037
|
+
length: number; // Note: This is needed to avoid being too lax with records types using number keys like `{0: string; 1: boolean}`.
|
|
1038
|
+
} ? (ConsistsOnlyOf<Key, StringDigit> extends true ? Strictify<Item, Options> : unknown) : Key extends keyof WithStringKeys<BaseType> ? StrictPropertyOf<WithStringKeys<BaseType>, Key, Options> : unknown;
|
|
1039
|
+
// 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.
|
|
1040
|
+
/**
|
|
1041
|
+
Get a deeply-nested property from an object using a key path, like Lodash's `.get()` function.
|
|
1042
|
+
|
|
1043
|
+
Use-case: Retrieve a property from deep inside an API response or some other complex object.
|
|
1044
|
+
|
|
1045
|
+
@example
|
|
1046
|
+
```
|
|
1047
|
+
import type {Get} from 'type-fest';
|
|
1048
|
+
import * as lodash from 'lodash';
|
|
1049
|
+
|
|
1050
|
+
const get = <BaseType, Path extends string | readonly string[]>(object: BaseType, path: Path): Get<BaseType, Path> =>
|
|
1051
|
+
lodash.get(object, path);
|
|
1052
|
+
|
|
1053
|
+
interface ApiResponse {
|
|
1054
|
+
hits: {
|
|
1055
|
+
hits: Array<{
|
|
1056
|
+
_id: string
|
|
1057
|
+
_source: {
|
|
1058
|
+
name: Array<{
|
|
1059
|
+
given: string[]
|
|
1060
|
+
family: string
|
|
1061
|
+
}>
|
|
1062
|
+
birthDate: string
|
|
1063
|
+
}
|
|
1064
|
+
}>
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
const getName = (apiResponse: ApiResponse) =>
|
|
1069
|
+
get(apiResponse, 'hits.hits[0]._source.name');
|
|
1070
|
+
//=> Array<{given: string[]; family: string}> | undefined
|
|
1071
|
+
|
|
1072
|
+
// Path also supports a readonly array of strings
|
|
1073
|
+
const getNameWithPathArray = (apiResponse: ApiResponse) =>
|
|
1074
|
+
get(apiResponse, ['hits','hits', '0', '_source', 'name'] as const);
|
|
1075
|
+
//=> Array<{given: string[]; family: string}> | undefined
|
|
1076
|
+
|
|
1077
|
+
// Non-strict mode:
|
|
1078
|
+
Get<string[], '3', {strict: false}> //=> string
|
|
1079
|
+
Get<Record<string, string>, 'foo', {strict: true}> // => string
|
|
1080
|
+
```
|
|
5
1081
|
|
|
1082
|
+
@category Object
|
|
1083
|
+
@category Array
|
|
1084
|
+
@category Template literal
|
|
1085
|
+
*/
|
|
1086
|
+
export type Get<BaseType, Path extends string | readonly string[], Options extends GetOptions = {}> = GetWithPath<BaseType, Path extends string ? ToPath<Path> : Path, Options>;
|
|
6
1087
|
export type ArrayOrPlainObject = UnknownArray | UnknownRecord;
|
|
7
1088
|
export type EventPosition = {
|
|
8
1089
|
x: number;
|
|
@@ -16,6 +1097,7 @@ export type GetterSetter<Value> = {
|
|
|
16
1097
|
};
|
|
17
1098
|
export type Key = number | string;
|
|
18
1099
|
export type PlainObject = UnknownRecord;
|
|
1100
|
+
type ToString$1<T> = T extends string | number ? `${T}` : never;
|
|
19
1101
|
export type UnknownArrayOrRecord = UnknownArray | UnknownRecord;
|
|
20
1102
|
/**
|
|
21
1103
|
* Chunks an array into smaller arrays of a specified size
|
|
@@ -917,7 +1999,7 @@ export declare function equal(first: unknown, second: unknown): boolean;
|
|
|
917
1999
|
* - You can retrieve a nested value by using dot notation, e.g., `foo.bar.baz`
|
|
918
2000
|
* - Returns `undefined` if the value is not found
|
|
919
2001
|
*/
|
|
920
|
-
export declare function getValue<Data extends PlainObject, Path extends Paths<Data>>(data: Data, path: Path): Get<Data, ToString<Path>>;
|
|
2002
|
+
export declare function getValue<Data extends PlainObject, Path extends Paths<Data>>(data: Data, path: Path): Get<Data, ToString$1<Path>>;
|
|
921
2003
|
/**
|
|
922
2004
|
* - Get the value from an object using an unknown path
|
|
923
2005
|
* - You can retrieve a nested value by using dot notation, e.g., `foo.bar.baz`
|
|
@@ -945,7 +2027,7 @@ export declare function setValue<Data extends PlainObject, Path extends Paths<Da
|
|
|
945
2027
|
*/
|
|
946
2028
|
export declare function setValue<Data extends PlainObject>(data: Data, path: string, value: unknown, ignoreCase?: boolean): Data;
|
|
947
2029
|
export type Smushed<Value> = Simplify<{
|
|
948
|
-
[Key in Paths<Value>]: Get<Value, ToString<Key>>;
|
|
2030
|
+
[Key in Paths<Value>]: Get<Value, ToString$1<Key>>;
|
|
949
2031
|
}>;
|
|
950
2032
|
/**
|
|
951
2033
|
* Smushes an object into a flat object with dot notation keys
|
|
@@ -964,12 +2046,8 @@ export declare function unsmush<Value extends PlainObject>(value: Value): Unsmus
|
|
|
964
2046
|
export declare function partial<Value extends PlainObject, Key extends keyof Value>(value: Value, keys: Key[]): Pick<Value, Key>;
|
|
965
2047
|
|
|
966
2048
|
export {
|
|
967
|
-
Get,
|
|
968
|
-
Paths,
|
|
969
|
-
Primitive,
|
|
970
2049
|
Timer$1 as Timer,
|
|
971
|
-
|
|
972
|
-
UnknownRecord,
|
|
2050
|
+
ToString$1 as ToString,
|
|
973
2051
|
findElement as $,
|
|
974
2052
|
findElements as $$,
|
|
975
2053
|
};
|
package/types/models.d.ts
CHANGED
|
@@ -12,5 +12,6 @@ export type GetterSetter<Value> = {
|
|
|
12
12
|
};
|
|
13
13
|
export type Key = number | string;
|
|
14
14
|
export type PlainObject = UnknownRecord;
|
|
15
|
+
export type ToString<T> = T extends string | number ? `${T}` : never;
|
|
15
16
|
export type UnknownArrayOrRecord = UnknownArray | UnknownRecord;
|
|
16
17
|
export type { Get, Paths, Primitive, UnknownArray, UnknownRecord };
|
package/types/value/get.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { ToString } from '
|
|
2
|
-
import type { Get, Paths, PlainObject } from '../models';
|
|
1
|
+
import type { Get, Paths, PlainObject, ToString } from '../models';
|
|
3
2
|
/**
|
|
4
3
|
* - Get the value from an object using a known path
|
|
5
4
|
* - You can retrieve a nested value by using dot notation, e.g., `foo.bar.baz`
|
package/types/value/smush.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Get, Paths, Simplify } from 'type-fest';
|
|
2
|
-
import type { ToString } from '
|
|
3
|
-
import type { PlainObject } from '../models';
|
|
2
|
+
import type { PlainObject, ToString } from '../models';
|
|
4
3
|
type Smushed<Value> = Simplify<{
|
|
5
4
|
[Key in Paths<Value>]: Get<Value, ToString<Key>>;
|
|
6
5
|
}>;
|