1 | import type {Primitive} from './primitive';
|
2 | import type {Simplify} from './simplify';
|
3 | import type {Trim} from './trim';
|
4 | import type {IsAny} from './is-any';
|
5 | import type {NegativeInfinity, PositiveInfinity} from './numeric';
|
6 | import type {GreaterThan} from './greater-than';
|
7 | import type {LessThan} from './less-than';
|
8 | import type {IsLiteral} from './is-literal';
|
9 | import type {UnknownRecord} from './unknown-record';
|
10 | import type {IsNever} from './is-never';
|
11 | import type {UnknownArray} from './unknown-array';
|
12 | import type {IsEqual} from './is-equal';
|
13 |
|
14 |
|
15 | export type {UnknownRecord} from './unknown-record';
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | type ArrayLength<T extends readonly unknown[]> = T extends {readonly length: infer L} ? L : never;
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 | export type TupleLength<T extends UnknownArray> =
|
43 |
|
44 |
|
45 | T extends unknown
|
46 | ? number extends T['length']
|
47 | ? never
|
48 | : T['length']
|
49 | : never;
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | export type BuildTuple<L extends number, Fill = unknown, T extends readonly unknown[] = []> = T['length'] extends L
|
59 | ? T
|
60 | : BuildTuple<L, Fill, [...T, Fill]>;
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | export type BuildObject<Key extends PropertyKey, Value, CopiedFrom extends object = {}> =
|
78 | Key extends keyof CopiedFrom
|
79 | ? Pick<{[_ in keyof CopiedFrom]: Value}, Key>
|
80 | : Key extends `${infer NumberKey extends number}`
|
81 | ? NumberKey extends keyof CopiedFrom
|
82 | ? Pick<{[_ in keyof CopiedFrom]: Value}, NumberKey>
|
83 | : {[_ in Key]: Value}
|
84 | : {[_ in Key]: Value};
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | export type ToString<T> = T extends string | number ? `${T}` : never;
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | export type BuiltIns = Primitive | void | Date | RegExp;
|
97 |
|
98 |
|
99 |
|
100 |
|
101 | export type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
|
102 |
|
103 | /**
|
104 | Returns a boolean for whether the given type is a plain key-value object.
|
105 | */
|
106 | export type IsPlainObject<T> =
|
107 | T extends NonRecursiveType | UnknownArray | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
|
108 | ? false
|
109 | : T extends object
|
110 | ? true
|
111 | : false;
|
112 |
|
113 | /**
|
114 | Converts a numeric string to a number.
|
115 |
|
116 | @example
|
117 | ```
|
118 | type PositiveInt = StringToNumber<'1234'>;
|
119 | //=> 1234
|
120 |
|
121 | type NegativeInt = StringToNumber<'-1234'>;
|
122 |
|
123 |
|
124 | type PositiveFloat = StringToNumber<'1234.56'>;
|
125 |
|
126 |
|
127 | type NegativeFloat = StringToNumber<'-1234.56'>;
|
128 |
|
129 |
|
130 | type PositiveInfinity = StringToNumber<'Infinity'>;
|
131 |
|
132 |
|
133 | type NegativeInfinity = StringToNumber<'-Infinity'>;
|
134 |
|
135 | ```
|
136 |
|
137 | @category String
|
138 | @category Numeric
|
139 | @category Template literal
|
140 | */
|
141 | export type StringToNumber<S extends string> = S extends `${infer N extends number}`
|
142 | ? N
|
143 | : S extends 'Infinity'
|
144 | ? PositiveInfinity
|
145 | : S extends '-Infinity'
|
146 | ? NegativeInfinity
|
147 | : never;
|
148 |
|
149 | /**
|
150 | Returns a boolean for whether the given string `S` starts with the given string `SearchString`.
|
151 |
|
152 | @example
|
153 | ```
|
154 | StartsWith<'abcde', 'abc'>;
|
155 |
|
156 |
|
157 | StartsWith<'abcde', 'bc'>;
|
158 |
|
159 |
|
160 | StartsWith<string, 'bc'>;
|
161 |
|
162 |
|
163 | StartsWith<'abcde', string>;
|
164 |
|
165 | ```
|
166 |
|
167 | @category String
|
168 | @category Template literal
|
169 | */
|
170 | export type StartsWith<S extends string, SearchString extends string> = string extends S | SearchString
|
171 | ? never
|
172 | : S extends `${SearchString}${infer T}`
|
173 | ? true
|
174 | : false;
|
175 |
|
176 | /**
|
177 | Returns the length of the given string.
|
178 |
|
179 | @example
|
180 | ```
|
181 | StringLength<'abcde'>;
|
182 |
|
183 |
|
184 | StringLength<string>;
|
185 |
|
186 | ```
|
187 |
|
188 | @category String
|
189 | @category Template literal
|
190 | */
|
191 | export type StringLength<S extends string> = string extends S
|
192 | ? never
|
193 | : StringToArray<S>['length'];
|
194 |
|
195 | /**
|
196 | Returns an array of the characters of the string.
|
197 |
|
198 | @example
|
199 | ```
|
200 | StringToArray<'abcde'>;
|
201 |
|
202 |
|
203 | StringToArray<string>;
|
204 |
|
205 | ```
|
206 |
|
207 | @category String
|
208 | */
|
209 | export type StringToArray<S extends string, Result extends string[] = []> = string extends S
|
210 | ? never
|
211 | : S extends `${infer F}${infer R}`
|
212 | ? StringToArray<R, [...Result, F]>
|
213 | : Result;
|
214 |
|
215 | export type UpperCaseCharacters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
|
216 |
|
217 | export type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
|
218 |
|
219 | export type Whitespace =
|
220 | | '\u{9}' // '\t'
|
221 | | '\u{A}' // '\n'
|
222 | | '\u{B}' // '\v'
|
223 | | '\u{C}' // '\f'
|
224 | | '\u{D}' // '\r'
|
225 | | '\u{20}' // ' '
|
226 | | '\u{85}'
|
227 | | '\u{A0}'
|
228 | | '\u{1680}'
|
229 | | '\u{2000}'
|
230 | | '\u{2001}'
|
231 | | '\u{2002}'
|
232 | | '\u{2003}'
|
233 | | '\u{2004}'
|
234 | | '\u{2005}'
|
235 | | '\u{2006}'
|
236 | | '\u{2007}'
|
237 | | '\u{2008}'
|
238 | | '\u{2009}'
|
239 | | '\u{200A}'
|
240 | | '\u{2028}'
|
241 | | '\u{2029}'
|
242 | | '\u{202F}'
|
243 | | '\u{205F}'
|
244 | | '\u{3000}'
|
245 | | '\u{FEFF}';
|
246 |
|
247 | export type WordSeparators = '-' | '_' | Whitespace;
|
248 |
|
249 | /**
|
250 | Matches any unknown array or tuple.
|
251 | */
|
252 | export type UnknownArrayOrTuple = readonly [...unknown[]];
|
253 |
|
254 | /**
|
255 | Matches any non empty tuple.
|
256 | */
|
257 | export type NonEmptyTuple = readonly [unknown, ...unknown[]];
|
258 |
|
259 | /**
|
260 | Returns a boolean for whether the two given types extends the base type.
|
261 | */
|
262 | export type IsBothExtends<BaseType, FirstType, SecondType> = FirstType extends BaseType
|
263 | ? SecondType extends BaseType
|
264 | ? true
|
265 | : false
|
266 | : false;
|
267 |
|
268 | /**
|
269 | Extracts the type of the first element of an array or tuple.
|
270 | */
|
271 | export type FirstArrayElement<TArray extends UnknownArrayOrTuple> = TArray extends readonly [infer THead, ...unknown[]]
|
272 | ? THead
|
273 | : never;
|
274 |
|
275 | /**
|
276 | Extracts the type of an array or tuple minus the first element.
|
277 | */
|
278 | export type ArrayTail<TArray extends UnknownArrayOrTuple> = TArray extends readonly [unknown, ...infer TTail] ? TTail : [];
|
279 |
|
280 | /**
|
281 | Extract the element of an array that also works for array union.
|
282 |
|
283 | Returns `never` if T is not an array.
|
284 |
|
285 | It creates a type-safe way to access the element type of `unknown` type.
|
286 | */
|
287 | export type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never;
|
288 |
|
289 | /**
|
290 | Extract the object field type if T is an object and K is a key of T, return `never` otherwise.
|
291 |
|
292 | It creates a type-safe way to access the member type of `unknown` type.
|
293 | */
|
294 | export type ObjectValue<T, K> =
|
295 | K extends keyof T
|
296 | ? T[K]
|
297 | : ToString<K> extends keyof T
|
298 | ? T[ToString<K>]
|
299 | : K extends `${infer NumberK extends number}`
|
300 | ? NumberK extends keyof T
|
301 | ? T[NumberK]
|
302 | : never
|
303 | : never;
|
304 |
|
305 | /**
|
306 | Returns a boolean for whether the string is lowercased.
|
307 | */
|
308 | export type IsLowerCase<T extends string> = T extends Lowercase<T> ? true : false;
|
309 |
|
310 | /**
|
311 | Returns a boolean for whether the string is uppercased.
|
312 | */
|
313 | export type IsUpperCase<T extends string> = T extends Uppercase<T> ? true : false;
|
314 |
|
315 | /**
|
316 | Returns a boolean for whether a string is whitespace.
|
317 | */
|
318 | export type IsWhitespace<T extends string> = T extends Whitespace
|
319 | ? true
|
320 | : T extends `${Whitespace}${infer Rest}`
|
321 | ? IsWhitespace<Rest>
|
322 | : false;
|
323 |
|
324 | /**
|
325 | Returns a boolean for whether the string is numeric.
|
326 |
|
327 | This type is a workaround for [Microsoft/TypeScript#46109](https://github.com/microsoft/TypeScript/issues/46109#issuecomment-930307987).
|
328 | */
|
329 | export type IsNumeric<T extends string> = T extends `${number}`
|
330 | ? Trim<T> extends T
|
331 | ? true
|
332 | : false
|
333 | : false;
|
334 |
|
335 | /**
|
336 | For an object T, if it has any properties that are a union with `undefined`, make those into optional properties instead.
|
337 |
|
338 | @example
|
339 | ```
|
340 | type User = {
|
341 | firstName: string;
|
342 | lastName: string | undefined;
|
343 | };
|
344 |
|
345 | type OptionalizedUser = UndefinedToOptional<User>;
|
346 |
|
347 |
|
348 |
|
349 |
|
350 | ```
|
351 | */
|
352 | export type UndefinedToOptional<T extends object> = Simplify<
|
353 | {
|
354 | // Property is not a union with `undefined`, keep it as-is.
|
355 | [Key in keyof Pick<T, FilterDefinedKeys<T>>]: T[Key];
|
356 | } & {
|
357 | // Property _is_ a union with defined value. Set as optional (via `?`) and remove `undefined` from the union.
|
358 | [Key in keyof Pick<T, FilterOptionalKeys<T>>]?: Exclude<T[Key], undefined>;
|
359 | }
|
360 | >;
|
361 |
|
362 | // Returns `never` if the key or property is not jsonable without testing whether the property is required or optional otherwise return the key.
|
363 | type BaseKeyFilter<Type, Key extends keyof Type> = Key extends symbol
|
364 | ? never
|
365 | : Type[Key] extends symbol
|
366 | ? never
|
367 | /*
|
368 | To prevent a problem where an object with only a `name` property is incorrectly treated as assignable to a function, we first check if the property is a record.
|
369 | This check is necessary, because without it, if we don't verify whether the property is a record, an object with a type of `{name: any}` would return `never` due to its potential assignability to a function.
|
370 | See: https://github.com/sindresorhus/type-fest/issues/657
|
371 | */
|
372 | : Type[Key] extends Record<string, unknown>
|
373 | ? Key
|
374 | : [(...arguments_: any[]) => any] extends [Type[Key]]
|
375 | ? never
|
376 | : Key;
|
377 |
|
378 | /**
|
379 | Returns the required keys.
|
380 | */
|
381 | type FilterDefinedKeys<T extends object> = Exclude<
|
382 | {
|
383 | [Key in keyof T]: IsAny<T[Key]> extends true
|
384 | ? Key
|
385 | : undefined extends T[Key]
|
386 | ? never
|
387 | : T[Key] extends undefined
|
388 | ? never
|
389 | : BaseKeyFilter<T, Key>;
|
390 | }[keyof T],
|
391 | undefined
|
392 | >;
|
393 |
|
394 | /**
|
395 | Returns the optional keys.
|
396 | */
|
397 | type FilterOptionalKeys<T extends object> = Exclude<
|
398 | {
|
399 | [Key in keyof T]: IsAny<T[Key]> extends true
|
400 | ? never
|
401 | : undefined extends T[Key]
|
402 | ? T[Key] extends undefined
|
403 | ? never
|
404 | : BaseKeyFilter<T, Key>
|
405 | : never;
|
406 | }[keyof T],
|
407 | undefined
|
408 | >;
|
409 |
|
410 | /**
|
411 | Test if the given function has multiple call signatures.
|
412 |
|
413 | Needed to handle the case of a single call signature with properties.
|
414 |
|
415 | Multiple call signatures cannot currently be supported due to a TypeScript limitation.
|
416 | @see https://github.com/microsoft/TypeScript/issues/29732
|
417 | */
|
418 | export type HasMultipleCallSignatures<T extends (...arguments_: any[]) => unknown> =
|
419 | T extends {(...arguments_: infer A): unknown; (...arguments_: infer B): unknown}
|
420 | ? B extends A
|
421 | ? A extends B
|
422 | ? false
|
423 | : true
|
424 | : true
|
425 | : false;
|
426 |
|
427 | /**
|
428 | Returns a boolean for whether the given `boolean` is not `false`.
|
429 | */
|
430 | export type IsNotFalse<T extends boolean> = [T] extends [false] ? false : true;
|
431 |
|
432 | /**
|
433 | Disallows any of the given keys.
|
434 | */
|
435 | export type RequireNone<KeysType extends PropertyKey> = Partial<Record<KeysType, never>>;
|
436 |
|
437 | /**
|
438 | Returns a boolean for whether the given type is primitive value or primitive type.
|
439 |
|
440 | @example
|
441 | ```
|
442 | IsPrimitive<'string'>
|
443 |
|
444 |
|
445 | IsPrimitive<string>
|
446 |
|
447 |
|
448 | IsPrimitive<Object>
|
449 |
|
450 | ```
|
451 | */
|
452 | export type IsPrimitive<T> = [T] extends [Primitive] ? true : false;
|
453 |
|
454 | /**
|
455 | Returns a boolean for whether A is false.
|
456 |
|
457 | @example
|
458 | ```
|
459 | Not<true>;
|
460 |
|
461 |
|
462 | Not<false>;
|
463 |
|
464 | ```
|
465 | */
|
466 | export type Not<A extends boolean> = A extends true
|
467 | ? false
|
468 | : A extends false
|
469 | ? true
|
470 | : never;
|
471 |
|
472 | /**
|
473 | Returns the maximum value from a tuple of integers.
|
474 |
|
475 | Note:
|
476 | - Float numbers are not supported.
|
477 |
|
478 | @example
|
479 | ```
|
480 | ArrayMax<[1, 2, 5, 3]>;
|
481 |
|
482 |
|
483 | ArrayMax<[1, 2, 5, 3, 99, -1]>;
|
484 |
|
485 | ```
|
486 | */
|
487 | export type ArrayMax<A extends number[], Result extends number = NegativeInfinity> = number extends A[number]
|
488 | ? never :
|
489 | A extends [infer F extends number, ...infer R extends number[]]
|
490 | ? GreaterThan<F, Result> extends true
|
491 | ? ArrayMax<R, F>
|
492 | : ArrayMax<R, Result>
|
493 | : Result;
|
494 |
|
495 | /**
|
496 | Returns the minimum value from a tuple of integers.
|
497 |
|
498 | Note:
|
499 | - Float numbers are not supported.
|
500 |
|
501 | @example
|
502 | ```
|
503 | ArrayMin<[1, 2, 5, 3]>;
|
504 |
|
505 |
|
506 | ArrayMin<[1, 2, 5, 3, -5]>;
|
507 |
|
508 | ```
|
509 | */
|
510 | export type ArrayMin<A extends number[], Result extends number = PositiveInfinity> = number extends A[number]
|
511 | ? never
|
512 | : A extends [infer F extends number, ...infer R extends number[]]
|
513 | ? LessThan<F, Result> extends true
|
514 | ? ArrayMin<R, F>
|
515 | : ArrayMin<R, Result>
|
516 | : Result;
|
517 |
|
518 | /**
|
519 | Returns the absolute value of a given value.
|
520 |
|
521 | @example
|
522 | ```
|
523 | NumberAbsolute<-1>;
|
524 |
|
525 |
|
526 | NumberAbsolute<1>;
|
527 |
|
528 |
|
529 | NumberAbsolute<NegativeInfinity>
|
530 |
|
531 | ```
|
532 | */
|
533 | export type NumberAbsolute<N extends number> = `${N}` extends `-${infer StringPositiveN}` ? StringToNumber<StringPositiveN> : N;
|
534 |
|
535 | /**
|
536 | 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.
|
537 |
|
538 | @example
|
539 | ```
|
540 | SameLengthPositiveNumericStringGt<'50', '10'>;
|
541 |
|
542 |
|
543 | SameLengthPositiveNumericStringGt<'10', '10'>;
|
544 |
|
545 | ```
|
546 | */
|
547 | type SameLengthPositiveNumericStringGt<A extends string, B extends string> = A extends `${infer FirstA}${infer RestA}`
|
548 | ? B extends `${infer FirstB}${infer RestB}`
|
549 | ? FirstA extends FirstB
|
550 | ? SameLengthPositiveNumericStringGt<RestA, RestB>
|
551 | : PositiveNumericCharacterGt<FirstA, FirstB>
|
552 | : never
|
553 | : false;
|
554 |
|
555 | type NumericString = '0123456789';
|
556 |
|
557 | /**
|
558 | Returns a boolean for whether `A` is greater than `B`, where `A` and `B` are both positive numeric strings.
|
559 |
|
560 | @example
|
561 | ```
|
562 | PositiveNumericStringGt<'500', '1'>;
|
563 |
|
564 |
|
565 | PositiveNumericStringGt<'1', '1'>;
|
566 |
|
567 |
|
568 | PositiveNumericStringGt<'1', '500'>;
|
569 |
|
570 | ```
|
571 | */
|
572 | export type PositiveNumericStringGt<A extends string, B extends string> = A extends B
|
573 | ? false
|
574 | : [BuildTuple<StringLength<A>, 0>, BuildTuple<StringLength<B>, 0>] extends infer R extends [readonly unknown[], readonly unknown[]]
|
575 | ? R[0] extends [...R[1], ...infer Remain extends readonly unknown[]]
|
576 | ? 0 extends Remain['length']
|
577 | ? SameLengthPositiveNumericStringGt<A, B>
|
578 | : true
|
579 | : false
|
580 | : never;
|
581 |
|
582 | /**
|
583 | Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both positive numeric characters.
|
584 |
|
585 | @example
|
586 | ```
|
587 | PositiveNumericCharacterGt<'5', '1'>;
|
588 |
|
589 |
|
590 | PositiveNumericCharacterGt<'1', '1'>;
|
591 |
|
592 | ```
|
593 | */
|
594 | type PositiveNumericCharacterGt<A extends string, B extends string> = NumericString extends `${infer HeadA}${A}${infer TailA}`
|
595 | ? NumericString extends `${infer HeadB}${B}${infer TailB}`
|
596 | ? HeadA extends `${HeadB}${infer _}${infer __}`
|
597 | ? true
|
598 | : false
|
599 | : never
|
600 | : never;
|
601 |
|
602 | /**
|
603 | Utility type to retrieve only literal keys from type.
|
604 | */
|
605 | export type LiteralKeyOf<T> = keyof {[K in keyof T as IsLiteral<K> extends true ? K : never]-?: never};
|
606 |
|
607 | /**
|
608 | Returns the static, fixed-length portion of the given array, excluding variable-length parts.
|
609 |
|
610 | @example
|
611 | ```
|
612 | type A = [string, number, boolean, ...string[]];
|
613 | type B = StaticPartOfArray<A>;
|
614 |
|
615 | ```
|
616 | */
|
617 | export type StaticPartOfArray<T extends UnknownArray, Result extends UnknownArray = []> =
|
618 | T extends unknown
|
619 | ? number extends T['length'] ?
|
620 | T extends readonly [infer U, ...infer V]
|
621 | ? StaticPartOfArray<V, [...Result, U]>
|
622 | : Result
|
623 | : T
|
624 | : never; // Should never happen
|
625 |
|
626 | /**
|
627 | Returns the variable, non-fixed-length portion of the given array, excluding static-length parts.
|
628 |
|
629 | @example
|
630 | ```
|
631 | type A = [string, number, boolean, ...string[]];
|
632 | type B = VariablePartOfArray<A>;
|
633 |
|
634 | ```
|
635 | */
|
636 | export type VariablePartOfArray<T extends UnknownArray> =
|
637 | T extends unknown
|
638 | ? T extends readonly [...StaticPartOfArray<T>, ...infer U]
|
639 | ? U
|
640 | : []
|
641 | : never; // Should never happen
|
642 |
|
643 | /**
|
644 | Returns the minimum number in the given union of numbers.
|
645 |
|
646 | Note: Just supports numbers from 0 to 999.
|
647 |
|
648 | @example
|
649 | ```
|
650 | type A = UnionMin<3 | 1 | 2>;
|
651 |
|
652 | ```
|
653 | */
|
654 | export type UnionMin<N extends number> = InternalUnionMin<N>;
|
655 |
|
656 | /**
|
657 | The actual implementation of `UnionMin`. It's private because it has some arguments that don't need to be exposed.
|
658 | */
|
659 | type InternalUnionMin<N extends number, T extends UnknownArray = []> =
|
660 | T['length'] extends N
|
661 | ? T['length']
|
662 | : InternalUnionMin<N, [...T, unknown]>;
|
663 |
|
664 | /**
|
665 | Returns the maximum number in the given union of numbers.
|
666 |
|
667 | Note: Just supports numbers from 0 to 999.
|
668 |
|
669 | @example
|
670 | ```
|
671 | type A = UnionMax<1 | 3 | 2>;
|
672 |
|
673 | ```
|
674 | */
|
675 | export type UnionMax<N extends number> = InternalUnionMax<N>;
|
676 |
|
677 | /**
|
678 | The actual implementation of `UnionMax`. It's private because it has some arguments that don't need to be exposed.
|
679 | */
|
680 | type InternalUnionMax<N extends number, T extends UnknownArray = []> =
|
681 | IsNever<N> extends true
|
682 | ? T['length']
|
683 | : T['length'] extends N
|
684 | ? InternalUnionMax<Exclude<N, T['length']>, T>
|
685 | : InternalUnionMax<N, [...T, unknown]>;
|
686 |
|
687 | /**
|
688 | Returns a boolean for whether the given type is a union type.
|
689 |
|
690 | @example
|
691 | ```
|
692 | type A = IsUnion<string | number>;
|
693 |
|
694 |
|
695 | type B = IsUnion<string>;
|
696 |
|
697 | ```
|
698 | */
|
699 | export type IsUnion<T> = InternalIsUnion<T>;
|
700 |
|
701 | /**
|
702 | The actual implementation of `IsUnion`.
|
703 | */
|
704 | type InternalIsUnion<T, U = T> =
|
705 | (
|
706 | // @link https://ghaiklor.github.io/type-challenges-solutions/en/medium-isunion.html
|
707 | IsNever<T> extends true
|
708 | ? false
|
709 | : T extends any
|
710 | ? [U] extends [T]
|
711 | ? false
|
712 | : true
|
713 | : never
|
714 | ) extends infer Result
|
715 | // In some cases `Result` will return `false | true` which is `boolean`,
|
716 | // that means `T` has at least two types and it's a union type,
|
717 | // so we will return `true` instead of `boolean`.
|
718 | ? boolean extends Result ? true
|
719 | : Result
|
720 | : never; // Should never happen
|
721 |
|
722 | /**
|
723 | Set the given array to readonly if `IsReadonly` is `true`, otherwise set the given array to normal, then return the result.
|
724 |
|
725 | @example
|
726 | ```
|
727 | type ReadonlyArray = readonly string[];
|
728 | type NormalArray = string[];
|
729 |
|
730 | type ReadonlyResult = SetArrayAccess<NormalArray, true>;
|
731 |
|
732 |
|
733 | type NormalResult = SetArrayAccess<ReadonlyArray, false>;
|
734 |
|
735 | ```
|
736 | */
|
737 | export type SetArrayAccess<T extends UnknownArray, IsReadonly extends boolean> =
|
738 | T extends readonly [...infer U] ?
|
739 | IsReadonly extends true
|
740 | ? readonly [...U]
|
741 | : [...U]
|
742 | : T;
|
743 |
|
744 | /**
|
745 | Returns whether the given array `T` is readonly.
|
746 | */
|
747 | export type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
|
748 |
|
749 | /**
|
750 | Get the exact version of the given `Key` in the given object `T`.
|
751 |
|
752 | Use-case: You known that a number key (e.g. 10) is in an object, but you don't know how it is defined in the object, as a string or as a number (e.g. 10 or '10'). You can use this type to get the exact version of the key. See the example.
|
753 |
|
754 | @example
|
755 | ```
|
756 | type Object = {
|
757 | 0: number;
|
758 | '1': string;
|
759 | };
|
760 |
|
761 | type Key1 = ExactKey<Object, '0'>;
|
762 |
|
763 | type Key2 = ExactKey<Object, 0>;
|
764 |
|
765 |
|
766 | type Key3 = ExactKey<Object, '1'>;
|
767 |
|
768 | type Key4 = ExactKey<Object, 1>;
|
769 |
|
770 | ```
|
771 |
|
772 | @category Object
|
773 | */
|
774 | export type ExactKey<T extends object, Key extends PropertyKey> =
|
775 | Key extends keyof T
|
776 | ? Key
|
777 | : ToString<Key> extends keyof T
|
778 | ? ToString<Key>
|
779 | : Key extends `${infer NumberKey extends number}`
|
780 | ? NumberKey extends keyof T
|
781 | ? NumberKey
|
782 | : never
|
783 | : never;
|
784 |
|
\ | No newline at end of file |