complete-common 1.0.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/LICENSE +9 -0
- package/README.md +7 -0
- package/dist/index.cjs +535 -0
- package/dist/index.d.cts +705 -0
- package/dist/index.d.mts +705 -0
- package/dist/index.d.ts +705 -0
- package/dist/index.mjs +463 -0
- package/package.json +36 -0
- package/src/constants.ts +3 -0
- package/src/functions/array.ts +209 -0
- package/src/functions/enums.ts +105 -0
- package/src/functions/map.ts +90 -0
- package/src/functions/math.ts +9 -0
- package/src/functions/object.ts +27 -0
- package/src/functions/random.ts +43 -0
- package/src/functions/set.ts +131 -0
- package/src/functions/sort.ts +18 -0
- package/src/functions/string.test.ts +42 -0
- package/src/functions/string.ts +304 -0
- package/src/functions/tuple.ts +31 -0
- package/src/functions/types.ts +15 -0
- package/src/functions/utils.test.ts +910 -0
- package/src/functions/utils.ts +238 -0
- package/src/index.ts +27 -0
- package/src/types/AddSubtract.ts +19 -0
- package/src/types/CompositionTypeSatisfiesEnum.ts +67 -0
- package/src/types/ERange.ts +15 -0
- package/src/types/IRange.ts +16 -0
- package/src/types/Immutable.ts +28 -0
- package/src/types/NaturalNumbersLessThan.ts +12 -0
- package/src/types/NaturalNumbersLessThanOrEqualTo.ts +14 -0
- package/src/types/ObjectValues.ts +1 -0
- package/src/types/ReadonlyMap.ts +12 -0
- package/src/types/ReadonlyRecord.ts +3 -0
- package/src/types/ReadonlySet.ts +9 -0
- package/src/types/Tuple.ts +14 -0
- package/src/types/WidenLiteral.ts +11 -0
- package/src/types/Writeable.ts +6 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// When regexes are located at the root instead of inside the function, the functions are tested to
|
|
2
|
+
// perform 11% faster.
|
|
3
|
+
|
|
4
|
+
const FLOAT_REGEX = /^-?\d*\.?\d+$/;
|
|
5
|
+
const INTEGER_REGEX = /^-?\d+$/;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Helper function to throw an error if the provided value is equal to `undefined`.
|
|
9
|
+
*
|
|
10
|
+
* This is useful to have TypeScript narrow a `T | undefined` value to `T` in a concise way.
|
|
11
|
+
*/
|
|
12
|
+
export function assertDefined<T>(
|
|
13
|
+
value: T,
|
|
14
|
+
...[msg]: [undefined] extends [T]
|
|
15
|
+
? [string]
|
|
16
|
+
: [
|
|
17
|
+
"The assertion is useless because the provided value does not contain undefined.",
|
|
18
|
+
]
|
|
19
|
+
): asserts value is Exclude<T, undefined> {
|
|
20
|
+
if (value === undefined) {
|
|
21
|
+
throw new TypeError(msg);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Helper function to throw an error if the provided value is equal to `null`.
|
|
27
|
+
*
|
|
28
|
+
* This is useful to have TypeScript narrow a `T | null` value to `T` in a concise way.
|
|
29
|
+
*/
|
|
30
|
+
export function assertNotNull<T>(
|
|
31
|
+
value: T,
|
|
32
|
+
...[msg]: [null] extends [T]
|
|
33
|
+
? [string]
|
|
34
|
+
: [
|
|
35
|
+
"The assertion is useless because the provided value does not contain null.",
|
|
36
|
+
]
|
|
37
|
+
): asserts value is Exclude<T, null> {
|
|
38
|
+
if (value === null) {
|
|
39
|
+
throw new TypeError(msg);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Helper function to get an iterator of integers with the specified range, inclusive on the lower
|
|
45
|
+
* end and exclusive on the high end. (The "e" in the function name stands for exclusive.) Thus,
|
|
46
|
+
* this function works in the same way as the built-in `range` function from Python.
|
|
47
|
+
*
|
|
48
|
+
* If the end is lower than the start, then an empty range will be returned.
|
|
49
|
+
*
|
|
50
|
+
* For example:
|
|
51
|
+
*
|
|
52
|
+
* - `eRange(2)` returns `[0, 1]`.
|
|
53
|
+
* - `eRange(3)` returns `[0, 1, 2]`.
|
|
54
|
+
* - `eRange(-3)` returns `[0, -1, -2]`.
|
|
55
|
+
* - `eRange(1, 3)` returns `[1, 2]`.
|
|
56
|
+
* - `eRange(2, 5)` returns `[2, 3, 4]`.
|
|
57
|
+
* - `eRange(5, 2)` returns `[]`.
|
|
58
|
+
* - `eRange(3, 3)` returns `[]`.
|
|
59
|
+
*
|
|
60
|
+
* If you want an array instead of an iterator, use the spread operator like this:
|
|
61
|
+
*
|
|
62
|
+
* ```ts
|
|
63
|
+
* const myArray = [...eRange(1, 3)];
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @param start The integer to start at.
|
|
67
|
+
* @param end Optional. The integer to end at. If not specified, then the start will be 0 and the
|
|
68
|
+
* first argument will be the end.
|
|
69
|
+
* @param increment Optional. The increment to use. Default is 1.
|
|
70
|
+
*/
|
|
71
|
+
export function* eRange(
|
|
72
|
+
start: number,
|
|
73
|
+
end?: number,
|
|
74
|
+
increment = 1,
|
|
75
|
+
): Generator<number> {
|
|
76
|
+
if (end === undefined) {
|
|
77
|
+
yield* eRange(0, start, increment);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
for (let i = start; i < end; i += increment) {
|
|
82
|
+
yield i;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Helper function to get an array of integers with the specified range, inclusive on both ends.
|
|
88
|
+
* (The "i" in the function name stands for inclusive.)
|
|
89
|
+
*
|
|
90
|
+
* If the end is lower than the start, then an empty range will be returned.
|
|
91
|
+
*
|
|
92
|
+
* For example:
|
|
93
|
+
*
|
|
94
|
+
* - `iRange(2)` returns `[0, 1, 2]`.
|
|
95
|
+
* - `iRange(3)` returns `[0, 1, 2, 3]`.
|
|
96
|
+
* - `iRange(-3)` returns `[0, -1, -2, -3]`.
|
|
97
|
+
* - `iRange(1, 3)` returns `[1, 2, 3]`.
|
|
98
|
+
* - `iRange(2, 5)` returns `[2, 3, 4, 5]`.
|
|
99
|
+
* - `iRange(5, 2)` returns `[]`.
|
|
100
|
+
* - `iRange(3, 3)` returns `[3]`.
|
|
101
|
+
*
|
|
102
|
+
* If you want an array instead of an iterator, use the spread operator like this:
|
|
103
|
+
*
|
|
104
|
+
* ```ts
|
|
105
|
+
* const myArray = [...eRange(1, 3)];
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @param start The integer to start at.
|
|
109
|
+
* @param end Optional. The integer to end at. If not specified, then the start will be 0 and the
|
|
110
|
+
* first argument will be the end.
|
|
111
|
+
* @param increment Optional. The increment to use. Default is 1.
|
|
112
|
+
*/
|
|
113
|
+
export function* iRange(
|
|
114
|
+
start: number,
|
|
115
|
+
end?: number,
|
|
116
|
+
increment = 1,
|
|
117
|
+
): Generator<number> {
|
|
118
|
+
if (end === undefined) {
|
|
119
|
+
yield* iRange(0, start, increment);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const exclusiveEnd = end + 1;
|
|
124
|
+
yield* eRange(start, exclusiveEnd, increment);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** From: https://stackoverflow.com/questions/61526746 */
|
|
128
|
+
export function isKeyOf<T extends object>(
|
|
129
|
+
key: PropertyKey,
|
|
130
|
+
target: T,
|
|
131
|
+
): key is keyof T {
|
|
132
|
+
return key in target;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Helper function to perform a no-op. This can be useful in order to make a trailing return valid
|
|
137
|
+
* in functions that use the early return pattern.
|
|
138
|
+
*/
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
140
|
+
export function noop(): void {}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* This is a more reliable version of `Number.parseFloat`:
|
|
144
|
+
*
|
|
145
|
+
* - `undefined` is returned instead of `Number.NaN`, which is helpful in conjunction with
|
|
146
|
+
* TypeScript type narrowing patterns.
|
|
147
|
+
* - Strings that are a mixture of numbers and letters will result in undefined instead of the part
|
|
148
|
+
* of the string that is the number. (e.g. "1a" --> undefined instead of "1a" --> 1)
|
|
149
|
+
* - Non-strings will result in undefined instead of being coerced to a number.
|
|
150
|
+
*
|
|
151
|
+
* @param string A string to convert to an integer.
|
|
152
|
+
*/
|
|
153
|
+
export function parseFloatSafe(string: string): number | undefined {
|
|
154
|
+
if (typeof string !== "string") {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const trimmedString = string.trim();
|
|
159
|
+
|
|
160
|
+
// If the string does not entirely consist of numbers, return undefined.
|
|
161
|
+
if (FLOAT_REGEX.exec(trimmedString) === null) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const number = Number.parseFloat(trimmedString);
|
|
166
|
+
return Number.isNaN(number) ? undefined : number;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* This is a more reliable version of `Number.parseInt`:
|
|
171
|
+
*
|
|
172
|
+
* - `undefined` is returned instead of `Number.NaN`, which is helpful in conjunction with
|
|
173
|
+
* TypeScript type narrowing patterns.
|
|
174
|
+
* - Strings that are a mixture of numbers and letters will result in undefined instead of the part
|
|
175
|
+
* of the string that is the number. (e.g. "1a" --> undefined instead of "1a" --> 1)
|
|
176
|
+
* - Non-strings will result in undefined instead of being coerced to a number.
|
|
177
|
+
*
|
|
178
|
+
* If you have to use a radix other than 10, use the vanilla `Number.parseInt` function instead,
|
|
179
|
+
* because this function ensures that the string contains no letters.
|
|
180
|
+
*/
|
|
181
|
+
export function parseIntSafe(string: string): number | undefined {
|
|
182
|
+
if (typeof string !== "string") {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const trimmedString = string.trim();
|
|
187
|
+
|
|
188
|
+
// If the string does not entirely consist of numbers, return undefined.
|
|
189
|
+
if (INTEGER_REGEX.exec(trimmedString) === null) {
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const number = Number.parseInt(trimmedString, 10);
|
|
194
|
+
return Number.isNaN(number) ? undefined : number;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Helper function to repeat code N times. This is faster to type and cleaner than using a for loop.
|
|
199
|
+
*
|
|
200
|
+
* For example:
|
|
201
|
+
*
|
|
202
|
+
* ```ts
|
|
203
|
+
* repeat(10, () => {
|
|
204
|
+
* foo();
|
|
205
|
+
* });
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* The repeated function is passed the index of the iteration, if needed:
|
|
209
|
+
*
|
|
210
|
+
* ```ts
|
|
211
|
+
* repeat(3, (i) => {
|
|
212
|
+
* console.log(i); // Prints "0", "1", "2"
|
|
213
|
+
* });
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export function repeat(num: number, func: (i: number) => void): void {
|
|
217
|
+
for (let i = 0; i < num; i++) {
|
|
218
|
+
func(i);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Helper function to signify that the enclosing code block is not yet complete. Using this function
|
|
224
|
+
* is similar to writing a "TODO" comment, but it has the benefit of preventing ESLint errors due to
|
|
225
|
+
* unused variables or early returns.
|
|
226
|
+
*
|
|
227
|
+
* When you see this function, it simply means that the programmer intends to add in more code to
|
|
228
|
+
* this spot later.
|
|
229
|
+
*
|
|
230
|
+
* This function is variadic, meaning that you can pass as many arguments as you want. (This is
|
|
231
|
+
* useful as a means to prevent unused variables.)
|
|
232
|
+
*
|
|
233
|
+
* This function does not actually do anything. (It is an "empty" function.)
|
|
234
|
+
*
|
|
235
|
+
* @allowEmptyVariadic
|
|
236
|
+
*/
|
|
237
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
|
|
238
|
+
export function todo(...args: readonly unknown[]): void {}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export * from "./constants.js";
|
|
2
|
+
export * from "./functions/array.js";
|
|
3
|
+
export * from "./functions/enums.js";
|
|
4
|
+
export * from "./functions/map.js";
|
|
5
|
+
export * from "./functions/math.js";
|
|
6
|
+
export * from "./functions/object.js";
|
|
7
|
+
export * from "./functions/random.js";
|
|
8
|
+
export * from "./functions/set.js";
|
|
9
|
+
export * from "./functions/sort.js";
|
|
10
|
+
export * from "./functions/string.js";
|
|
11
|
+
export * from "./functions/tuple.js";
|
|
12
|
+
export * from "./functions/types.js";
|
|
13
|
+
export * from "./functions/utils.js";
|
|
14
|
+
export * from "./types/AddSubtract.js";
|
|
15
|
+
export * from "./types/CompositionTypeSatisfiesEnum.js";
|
|
16
|
+
export * from "./types/ERange.js";
|
|
17
|
+
export * from "./types/Immutable.js";
|
|
18
|
+
export * from "./types/IRange.js";
|
|
19
|
+
export * from "./types/NaturalNumbersLessThan.js";
|
|
20
|
+
export * from "./types/NaturalNumbersLessThanOrEqualTo.js";
|
|
21
|
+
export * from "./types/ObjectValues.js";
|
|
22
|
+
export * from "./types/ReadonlyMap.js";
|
|
23
|
+
export * from "./types/ReadonlyRecord.js";
|
|
24
|
+
export * from "./types/ReadonlySet.js";
|
|
25
|
+
export * from "./types/Tuple.js";
|
|
26
|
+
export * from "./types/WidenLiteral.js";
|
|
27
|
+
export * from "./types/Writeable.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** From: https://gist.github.com/ryandabler/8b4ff4f36aed47bc09acc03174638468 */
|
|
2
|
+
export type Add<A extends number, B extends number> = Length<
|
|
3
|
+
[...BuildTuple<A>, ...BuildTuple<B>]
|
|
4
|
+
>;
|
|
5
|
+
|
|
6
|
+
/** From: https://gist.github.com/ryandabler/8b4ff4f36aed47bc09acc03174638468 */
|
|
7
|
+
export type Subtract<A extends number, B extends number> = A extends A
|
|
8
|
+
? BuildTuple<A> extends [...infer U, ...BuildTuple<B>]
|
|
9
|
+
? Length<U>
|
|
10
|
+
: never
|
|
11
|
+
: never;
|
|
12
|
+
|
|
13
|
+
type BuildTuple<L extends number, T extends unknown[] = []> = T extends {
|
|
14
|
+
length: L;
|
|
15
|
+
}
|
|
16
|
+
? T
|
|
17
|
+
: BuildTuple<L, [...T, unknown]>;
|
|
18
|
+
|
|
19
|
+
type Length<T extends unknown[]> = T extends { length: infer L } ? L : never;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper type to validate that a union of interfaces with a field of `type` that is based on an
|
|
3
|
+
* enum is complete.
|
|
4
|
+
*
|
|
5
|
+
* For example:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* enum ObjectiveType {
|
|
9
|
+
* Foo,
|
|
10
|
+
* Bar,
|
|
11
|
+
* Baz,
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* interface FooObjective {
|
|
15
|
+
* type: ObjectiveType.Foo;
|
|
16
|
+
* fooThing: number;
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* interface BarObjective {
|
|
20
|
+
* type: ObjectiveType.Bar;
|
|
21
|
+
* barThing: string;
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* type Objective = FooObjective | BarObjective;
|
|
25
|
+
* type _Test = CompositionTypeSatisfiesEnum<Objective, ObjectiveType>;
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* In this example, `Test` would be flagged by TypeScript because `Objective` does not contain an
|
|
29
|
+
* entry for `BazObjective`.
|
|
30
|
+
*/
|
|
31
|
+
export type CompositionTypeSatisfiesEnum<
|
|
32
|
+
T extends { type: unknown },
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
34
|
+
Enum extends T["type"],
|
|
35
|
+
> = unknown;
|
|
36
|
+
|
|
37
|
+
// -----
|
|
38
|
+
// Tests
|
|
39
|
+
// -----
|
|
40
|
+
|
|
41
|
+
enum ObjectiveType {
|
|
42
|
+
Foo = "Foo",
|
|
43
|
+
Bar = "Bar",
|
|
44
|
+
Baz = "Baz",
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface FooObjective {
|
|
48
|
+
type: ObjectiveType.Foo;
|
|
49
|
+
fooThing: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface BarObjective {
|
|
53
|
+
type: ObjectiveType.Bar;
|
|
54
|
+
barThing: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface BazObjective {
|
|
58
|
+
type: ObjectiveType.Baz;
|
|
59
|
+
bazThing: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type Objective1 = FooObjective | BarObjective | BazObjective;
|
|
63
|
+
type _Test1 = CompositionTypeSatisfiesEnum<Objective1, ObjectiveType>;
|
|
64
|
+
|
|
65
|
+
type Objective2 = FooObjective | BarObjective;
|
|
66
|
+
// @ts-expect-error Missing "Baz".
|
|
67
|
+
type _Test2 = CompositionTypeSatisfiesEnum<Objective2, ObjectiveType>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { NaturalNumbersLessThan } from "./NaturalNumbersLessThan.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Helper type to get a range of integers. It is inclusive on the lower end and exclusive on the
|
|
5
|
+
* high end. (The "E" in the type name stands for exclusive.)
|
|
6
|
+
*
|
|
7
|
+
* For example, `ERange<3, 5>` will return `3 | 4`.
|
|
8
|
+
*
|
|
9
|
+
* From:
|
|
10
|
+
* https://stackoverflow.com/questions/39494689/is-it-possible-to-restrict-number-to-a-certain-range
|
|
11
|
+
*/
|
|
12
|
+
export type ERange<Low extends number, High extends number> = Exclude<
|
|
13
|
+
NaturalNumbersLessThan<High>,
|
|
14
|
+
NaturalNumbersLessThan<Low>
|
|
15
|
+
>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { NaturalNumbersLessThan } from "./NaturalNumbersLessThan.js";
|
|
2
|
+
import type { NaturalNumbersLessThanOrEqualTo } from "./NaturalNumbersLessThanOrEqualTo.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Helper type to get a range of integers. It is inclusive on both ends. (The "I" in the type name
|
|
6
|
+
* stands for inclusive.)
|
|
7
|
+
*
|
|
8
|
+
* For example, `IRange<3, 5>` will return `3 | 4 | 5`.
|
|
9
|
+
*
|
|
10
|
+
* From:
|
|
11
|
+
* https://stackoverflow.com/questions/39494689/is-it-possible-to-restrict-number-to-a-certain-range
|
|
12
|
+
*/
|
|
13
|
+
export type IRange<Low extends number, High extends number> = Exclude<
|
|
14
|
+
NaturalNumbersLessThanOrEqualTo<High>,
|
|
15
|
+
NaturalNumbersLessThan<Low>
|
|
16
|
+
>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Immutable is a utility type that will make the given array/map/set/object recursively read-only.
|
|
3
|
+
*
|
|
4
|
+
* You can use this type to easily build safe data structures.
|
|
5
|
+
*
|
|
6
|
+
* From: https://stackoverflow.com/questions/41879327/deepreadonly-object-typescript
|
|
7
|
+
*/
|
|
8
|
+
export type Immutable<T> = T extends ImmutablePrimitive
|
|
9
|
+
? T
|
|
10
|
+
: T extends Array<infer U>
|
|
11
|
+
? ImmutableArray<U>
|
|
12
|
+
: T extends Map<infer K, infer V>
|
|
13
|
+
? ImmutableMap<K, V>
|
|
14
|
+
: T extends Set<infer M>
|
|
15
|
+
? ImmutableSet<M>
|
|
16
|
+
: ImmutableObject<T>;
|
|
17
|
+
|
|
18
|
+
type ImmutablePrimitive =
|
|
19
|
+
| undefined
|
|
20
|
+
| null
|
|
21
|
+
| boolean
|
|
22
|
+
| string
|
|
23
|
+
| number
|
|
24
|
+
| Function; // eslint-disable-line @typescript-eslint/no-unsafe-function-type
|
|
25
|
+
type ImmutableArray<T> = ReadonlyArray<Immutable<T>>;
|
|
26
|
+
type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;
|
|
27
|
+
type ImmutableSet<T> = ReadonlySet<Immutable<T>>;
|
|
28
|
+
type ImmutableObject<T> = { readonly [K in keyof T]: Immutable<T[K]> };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper type to get a range of integers between 0 and N - 1.
|
|
3
|
+
*
|
|
4
|
+
* From:
|
|
5
|
+
* https://stackoverflow.com/questions/39494689/is-it-possible-to-restrict-number-to-a-certain-range
|
|
6
|
+
*/
|
|
7
|
+
export type NaturalNumbersLessThan<
|
|
8
|
+
N extends number,
|
|
9
|
+
Acc extends number[] = [],
|
|
10
|
+
> = Acc["length"] extends N
|
|
11
|
+
? Acc[number]
|
|
12
|
+
: NaturalNumbersLessThan<N, [...Acc, Acc["length"]]>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper type to get a range of integers between 0 and N.
|
|
3
|
+
*
|
|
4
|
+
* From:
|
|
5
|
+
* https://stackoverflow.com/questions/39494689/is-it-possible-to-restrict-number-to-a-certain-range
|
|
6
|
+
*/
|
|
7
|
+
export type NaturalNumbersLessThanOrEqualTo<
|
|
8
|
+
N extends number,
|
|
9
|
+
T extends number[] = [],
|
|
10
|
+
> = T extends [unknown, ...infer Tail]
|
|
11
|
+
? Tail["length"] extends N
|
|
12
|
+
? T[number]
|
|
13
|
+
: NaturalNumbersLessThanOrEqualTo<N, [...T, T["length"]]>
|
|
14
|
+
: NaturalNumbersLessThanOrEqualTo<N, [...T, T["length"]]>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ObjectValues<T> = T[keyof T];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
interface ReadonlyMapConstructor {
|
|
4
|
+
new (): ReadonlyMap<any, any>;
|
|
5
|
+
new <K, V>(
|
|
6
|
+
entries?: ReadonlyArray<readonly [K, V]> | Iterable<readonly [K, V]> | null,
|
|
7
|
+
): ReadonlyMap<K, V>;
|
|
8
|
+
readonly prototype: ReadonlyMap<any, any>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** An alias for the `Map` constructor that returns a read-only map. */
|
|
12
|
+
export const ReadonlyMap = Map as ReadonlyMapConstructor;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
interface ReadonlySetConstructor {
|
|
4
|
+
new <T = any>(values?: readonly T[] | Iterable<T> | null): ReadonlySet<T>;
|
|
5
|
+
readonly prototype: ReadonlySet<any>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** An alias for the `Set` constructor that returns a read-only set. */
|
|
9
|
+
export const ReadonlySet = Set as ReadonlySetConstructor;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper type to represent a tuple of length N.
|
|
3
|
+
*
|
|
4
|
+
* From:
|
|
5
|
+
* https://stackoverflow.com/questions/52489261/typescript-can-i-define-an-n-length-tuple-type/52490977#52490977
|
|
6
|
+
*/
|
|
7
|
+
export type Tuple<T, N extends number> = N extends N
|
|
8
|
+
? number extends N
|
|
9
|
+
? T[]
|
|
10
|
+
: _TupleOf<T, N, []>
|
|
11
|
+
: never;
|
|
12
|
+
type _TupleOf<T, N extends number, R extends unknown[]> = R["length"] extends N
|
|
13
|
+
? R
|
|
14
|
+
: _TupleOf<T, N, [T, ...R]>;
|