UNPKG

19.5 kBTypeScriptView Raw
1import type {Primitive} from './primitive';
2import type {Simplify} from './simplify';
3import type {Trim} from './trim';
4import type {IsAny} from './is-any';
5import type {NegativeInfinity, PositiveInfinity} from './numeric';
6import type {GreaterThan} from './greater-than';
7import type {LessThan} from './less-than';
8import type {IsLiteral} from './is-literal';
9import type {UnknownRecord} from './unknown-record';
10import type {IsNever} from './is-never';
11import type {UnknownArray} from './unknown-array';
12import type {IsEqual} from './is-equal';
13
14// TODO: Remove for v5.
15export type {UnknownRecord} from './unknown-record';
16
17/**
18Infer the length of the given array `<T>`.
19
20@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
21*/
22type ArrayLength<T extends readonly unknown[]> = T extends {readonly length: infer L} ? L : never;
23
24/**
25Infer the length of the given tuple `<T>`.
26
27Returns `never` if the given type is an non-fixed-length array like `Array<string>`.
28
29@example
30```
31type Tuple = TupleLength<[string, number, boolean]>;
32//=> 3
33
34type Array = TupleLength<string[]>;
35//=> never
36
37// Supports union types.
38type Union = TupleLength<[] | [1, 2, 3] | Array<number>>;
39//=> 1 | 3
40```
41*/
42export type TupleLength<T extends UnknownArray> =
43 // `extends unknown` is used to convert `T` (if `T` is a union type) to
44 // a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types))
45 T extends unknown
46 ? number extends T['length']
47 ? never // Return never if the given type is an non-flexed-length array like `Array<string>`
48 : T['length']
49 : never; // Should never happen
50
51/**
52Create a tuple type of the given length `<L>` and fill it with the given type `<Fill>`.
53
54If `<Fill>` is not provided, it will default to `unknown`.
55
56@link https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f
57*/
58export 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/**
63Create an object type with the given key `<Key>` and value `<Value>`.
64
65It will copy the prefix and optional status of the same key from the given object `CopiedFrom` into the result.
66
67@example
68```
69type A = BuildObject<'a', string>;
70//=> {a: string}
71
72// Copy `readonly` and `?` from the key `a` of `{readonly a?: any}`
73type B = BuildObject<'a', string, {readonly a?: any}>;
74//=> {readonly a?: string}
75```
76*/
77export 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/**
87Return a string representation of the given string or number.
88
89Note: This type is not the return type of the `.toString()` function.
90*/
91export type ToString<T> = T extends string | number ? `${T}` : never;
92
93/**
94Matches any primitive, `void`, `Date`, or `RegExp` value.
95*/
96export type BuiltIns = Primitive | void | Date | RegExp;
97
98/**
99Matches non-recursive types.
100*/
101export type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
102
103/**
104Returns a boolean for whether the given type is a plain key-value object.
105*/
106export 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/**
114Converts a numeric string to a number.
115
116@example
117```
118type PositiveInt = StringToNumber<'1234'>;
119//=> 1234
120
121type NegativeInt = StringToNumber<'-1234'>;
122//=> -1234
123
124type PositiveFloat = StringToNumber<'1234.56'>;
125//=> 1234.56
126
127type NegativeFloat = StringToNumber<'-1234.56'>;
128//=> -1234.56
129
130type PositiveInfinity = StringToNumber<'Infinity'>;
131//=> Infinity
132
133type NegativeInfinity = StringToNumber<'-Infinity'>;
134//=> -Infinity
135```
136
137@category String
138@category Numeric
139@category Template literal
140*/
141export 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/**
150Returns a boolean for whether the given string `S` starts with the given string `SearchString`.
151
152@example
153```
154StartsWith<'abcde', 'abc'>;
155//=> true
156
157StartsWith<'abcde', 'bc'>;
158//=> false
159
160StartsWith<string, 'bc'>;
161//=> never
162
163StartsWith<'abcde', string>;
164//=> never
165```
166
167@category String
168@category Template literal
169*/
170export 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/**
177Returns the length of the given string.
178
179@example
180```
181StringLength<'abcde'>;
182//=> 5
183
184StringLength<string>;
185//=> never
186```
187
188@category String
189@category Template literal
190*/
191export type StringLength<S extends string> = string extends S
192 ? never
193 : StringToArray<S>['length'];
194
195/**
196Returns an array of the characters of the string.
197
198@example
199```
200StringToArray<'abcde'>;
201//=> ['a', 'b', 'c', 'd', 'e']
202
203StringToArray<string>;
204//=> never
205```
206
207@category String
208*/
209export 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
215export 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
217export type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
218
219export 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
247export type WordSeparators = '-' | '_' | Whitespace;
248
249/**
250Matches any unknown array or tuple.
251*/
252export type UnknownArrayOrTuple = readonly [...unknown[]];
253
254/**
255Matches any non empty tuple.
256*/
257export type NonEmptyTuple = readonly [unknown, ...unknown[]];
258
259/**
260Returns a boolean for whether the two given types extends the base type.
261*/
262export type IsBothExtends<BaseType, FirstType, SecondType> = FirstType extends BaseType
263 ? SecondType extends BaseType
264 ? true
265 : false
266 : false;
267
268/**
269Extracts the type of the first element of an array or tuple.
270*/
271export type FirstArrayElement<TArray extends UnknownArrayOrTuple> = TArray extends readonly [infer THead, ...unknown[]]
272 ? THead
273 : never;
274
275/**
276Extracts the type of an array or tuple minus the first element.
277*/
278export type ArrayTail<TArray extends UnknownArrayOrTuple> = TArray extends readonly [unknown, ...infer TTail] ? TTail : [];
279
280/**
281Extract the element of an array that also works for array union.
282
283Returns `never` if T is not an array.
284
285It creates a type-safe way to access the element type of `unknown` type.
286*/
287export type ArrayElement<T> = T extends readonly unknown[] ? T[0] : never;
288
289/**
290Extract the object field type if T is an object and K is a key of T, return `never` otherwise.
291
292It creates a type-safe way to access the member type of `unknown` type.
293*/
294export 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/**
306Returns a boolean for whether the string is lowercased.
307*/
308export type IsLowerCase<T extends string> = T extends Lowercase<T> ? true : false;
309
310/**
311Returns a boolean for whether the string is uppercased.
312*/
313export type IsUpperCase<T extends string> = T extends Uppercase<T> ? true : false;
314
315/**
316Returns a boolean for whether a string is whitespace.
317*/
318export type IsWhitespace<T extends string> = T extends Whitespace
319 ? true
320 : T extends `${Whitespace}${infer Rest}`
321 ? IsWhitespace<Rest>
322 : false;
323
324/**
325Returns a boolean for whether the string is numeric.
326
327This type is a workaround for [Microsoft/TypeScript#46109](https://github.com/microsoft/TypeScript/issues/46109#issuecomment-930307987).
328*/
329export type IsNumeric<T extends string> = T extends `${number}`
330 ? Trim<T> extends T
331 ? true
332 : false
333 : false;
334
335/**
336For an object T, if it has any properties that are a union with `undefined`, make those into optional properties instead.
337
338@example
339```
340type User = {
341 firstName: string;
342 lastName: string | undefined;
343};
344
345type OptionalizedUser = UndefinedToOptional<User>;
346//=> {
347// firstName: string;
348// lastName?: string;
349// }
350```
351*/
352export 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.
363type 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/**
379Returns the required keys.
380*/
381type 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],
391undefined
392>;
393
394/**
395Returns the optional keys.
396*/
397type 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],
407undefined
408>;
409
410/**
411Test if the given function has multiple call signatures.
412
413Needed to handle the case of a single call signature with properties.
414
415Multiple call signatures cannot currently be supported due to a TypeScript limitation.
416@see https://github.com/microsoft/TypeScript/issues/29732
417*/
418export 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/**
428Returns a boolean for whether the given `boolean` is not `false`.
429*/
430export type IsNotFalse<T extends boolean> = [T] extends [false] ? false : true;
431
432/**
433Disallows any of the given keys.
434*/
435export type RequireNone<KeysType extends PropertyKey> = Partial<Record<KeysType, never>>;
436
437/**
438Returns a boolean for whether the given type is primitive value or primitive type.
439
440@example
441```
442IsPrimitive<'string'>
443//=> true
444
445IsPrimitive<string>
446//=> true
447
448IsPrimitive<Object>
449//=> false
450```
451*/
452export type IsPrimitive<T> = [T] extends [Primitive] ? true : false;
453
454/**
455Returns a boolean for whether A is false.
456
457@example
458```
459Not<true>;
460//=> false
461
462Not<false>;
463//=> true
464```
465*/
466export type Not<A extends boolean> = A extends true
467 ? false
468 : A extends false
469 ? true
470 : never;
471
472/**
473Returns the maximum value from a tuple of integers.
474
475Note:
476- Float numbers are not supported.
477
478@example
479```
480ArrayMax<[1, 2, 5, 3]>;
481//=> 5
482
483ArrayMax<[1, 2, 5, 3, 99, -1]>;
484//=> 99
485```
486*/
487export 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/**
496Returns the minimum value from a tuple of integers.
497
498Note:
499- Float numbers are not supported.
500
501@example
502```
503ArrayMin<[1, 2, 5, 3]>;
504//=> 1
505
506ArrayMin<[1, 2, 5, 3, -5]>;
507//=> -5
508```
509*/
510export 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/**
519Returns the absolute value of a given value.
520
521@example
522```
523NumberAbsolute<-1>;
524//=> 1
525
526NumberAbsolute<1>;
527//=> 1
528
529NumberAbsolute<NegativeInfinity>
530//=> PositiveInfinity
531```
532*/
533export type NumberAbsolute<N extends number> = `${N}` extends `-${infer StringPositiveN}` ? StringToNumber<StringPositiveN> : N;
534
535/**
536Returns 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```
540SameLengthPositiveNumericStringGt<'50', '10'>;
541//=> true
542
543SameLengthPositiveNumericStringGt<'10', '10'>;
544//=> false
545```
546*/
547type 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
555type NumericString = '0123456789';
556
557/**
558Returns a boolean for whether `A` is greater than `B`, where `A` and `B` are both positive numeric strings.
559
560@example
561```
562PositiveNumericStringGt<'500', '1'>;
563//=> true
564
565PositiveNumericStringGt<'1', '1'>;
566//=> false
567
568PositiveNumericStringGt<'1', '500'>;
569//=> false
570```
571*/
572export 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/**
583Returns a boolean for whether `A` represents a number greater than `B`, where `A` and `B` are both positive numeric characters.
584
585@example
586```
587PositiveNumericCharacterGt<'5', '1'>;
588//=> true
589
590PositiveNumericCharacterGt<'1', '1'>;
591//=> false
592```
593*/
594type 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/**
603Utility type to retrieve only literal keys from type.
604*/
605export type LiteralKeyOf<T> = keyof {[K in keyof T as IsLiteral<K> extends true ? K : never]-?: never};
606
607/**
608Returns the static, fixed-length portion of the given array, excluding variable-length parts.
609
610@example
611```
612type A = [string, number, boolean, ...string[]];
613type B = StaticPartOfArray<A>;
614//=> [string, number, boolean]
615```
616*/
617export 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/**
627Returns the variable, non-fixed-length portion of the given array, excluding static-length parts.
628
629@example
630```
631type A = [string, number, boolean, ...string[]];
632type B = VariablePartOfArray<A>;
633//=> string[]
634```
635*/
636export 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/**
644Returns the minimum number in the given union of numbers.
645
646Note: Just supports numbers from 0 to 999.
647
648@example
649```
650type A = UnionMin<3 | 1 | 2>;
651//=> 1
652```
653*/
654export type UnionMin<N extends number> = InternalUnionMin<N>;
655
656/**
657The actual implementation of `UnionMin`. It's private because it has some arguments that don't need to be exposed.
658*/
659type InternalUnionMin<N extends number, T extends UnknownArray = []> =
660 T['length'] extends N
661 ? T['length']
662 : InternalUnionMin<N, [...T, unknown]>;
663
664/**
665Returns the maximum number in the given union of numbers.
666
667Note: Just supports numbers from 0 to 999.
668
669@example
670```
671type A = UnionMax<1 | 3 | 2>;
672//=> 3
673```
674*/
675export type UnionMax<N extends number> = InternalUnionMax<N>;
676
677/**
678The actual implementation of `UnionMax`. It's private because it has some arguments that don't need to be exposed.
679*/
680type 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/**
688Returns a boolean for whether the given type is a union type.
689
690@example
691```
692type A = IsUnion<string | number>;
693//=> true
694
695type B = IsUnion<string>;
696//=> false
697```
698*/
699export type IsUnion<T> = InternalIsUnion<T>;
700
701/**
702The actual implementation of `IsUnion`.
703*/
704type 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/**
723Set the given array to readonly if `IsReadonly` is `true`, otherwise set the given array to normal, then return the result.
724
725@example
726```
727type ReadonlyArray = readonly string[];
728type NormalArray = string[];
729
730type ReadonlyResult = SetArrayAccess<NormalArray, true>;
731//=> readonly string[]
732
733type NormalResult = SetArrayAccess<ReadonlyArray, false>;
734//=> string[]
735```
736*/
737export type SetArrayAccess<T extends UnknownArray, IsReadonly extends boolean> =
738T extends readonly [...infer U] ?
739 IsReadonly extends true
740 ? readonly [...U]
741 : [...U]
742 : T;
743
744/**
745Returns whether the given array `T` is readonly.
746*/
747export type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
748
749/**
750Get the exact version of the given `Key` in the given object `T`.
751
752Use-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```
756type Object = {
757 0: number;
758 '1': string;
759};
760
761type Key1 = ExactKey<Object, '0'>;
762//=> 0
763type Key2 = ExactKey<Object, 0>;
764//=> 0
765
766type Key3 = ExactKey<Object, '1'>;
767//=> '1'
768type Key4 = ExactKey<Object, 1>;
769//=> '1'
770```
771
772@category Object
773*/
774export type ExactKey<T extends object, Key extends PropertyKey> =
775Key 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