|
| 1 | +import type {If} from './if.d.ts'; |
| 2 | +import type {IsArrayReadonly} from './internal/array.d.ts'; |
| 3 | +import type {IfNotAnyOrNever, IsExactOptionalPropertyTypesEnabled} from './internal/type.d.ts'; |
| 4 | +import type {IsOptionalKeyOf} from './is-optional-key-of.d.ts'; |
| 5 | +import type {UnknownArray} from './unknown-array.d.ts'; |
| 6 | + |
| 7 | +/** |
| 8 | +Reverse the order of elements in a tuple type. |
| 9 | +
|
| 10 | +@example |
| 11 | +```ts |
| 12 | +import type {ArrayReverse} from 'type-fest'; |
| 13 | +
|
| 14 | +type A = ArrayReverse<[string, number, boolean]>; |
| 15 | +//=> [boolean, number, string] |
| 16 | +
|
| 17 | +type B = ArrayReverse<readonly [string, number, ...boolean[]]>; |
| 18 | +//=> readonly [...boolean[], number, string] |
| 19 | +
|
| 20 | +type C = ArrayReverse<['foo', 'bar'] | readonly [1, 2, 3]>; |
| 21 | +//=> ["bar", "foo"] | readonly [3, 2, 1] |
| 22 | +
|
| 23 | +type D = ArrayReverse<string[]>; |
| 24 | +//=> string[] |
| 25 | +
|
| 26 | +type E = ArrayReverse<[]>; |
| 27 | +//=> [] |
| 28 | +``` |
| 29 | +
|
| 30 | +Note: If the tuple contains optional elements, the result will be a union of tuples, refer to the examples below: |
| 31 | +
|
| 32 | +@example |
| 33 | +```ts |
| 34 | +import type {ArrayReverse} from 'type-fest'; |
| 35 | +
|
| 36 | +type A = ArrayReverse<[string, number, boolean?]>; |
| 37 | +//=> [boolean, number, string] | [number, string] |
| 38 | +
|
| 39 | +type B = ArrayReverse<[string, number?, boolean?]>; |
| 40 | +//=> [boolean, number, string] | [number, string] | [string] |
| 41 | +
|
| 42 | +type C = ArrayReverse<[string?, number?, boolean?]>; |
| 43 | +//=> [boolean, number, string] | [number, string] | [string] | [] |
| 44 | +
|
| 45 | +type D = ArrayReverse<[string, number?, ...boolean[]]>; |
| 46 | +//=> [...boolean[], number, string] | [string] |
| 47 | +
|
| 48 | +type E = ArrayReverse<[string?, number?, ...boolean[]]>; |
| 49 | +//=> [...boolean[], number, string] | [string] | [] |
| 50 | +``` |
| 51 | +
|
| 52 | +@category Array |
| 53 | +*/ |
| 54 | +export type ArrayReverse<TArray extends UnknownArray> = IfNotAnyOrNever<TArray, |
| 55 | + TArray extends unknown // For distributing `TArray` |
| 56 | + ? _ArrayReverse<TArray> extends infer Result |
| 57 | + ? If<IsArrayReadonly<TArray>, Readonly<Result>, Result> |
| 58 | + : never // Should never happen |
| 59 | + : never>; // Should never happen |
| 60 | + |
| 61 | +type _ArrayReverse< |
| 62 | + TArray extends UnknownArray, |
| 63 | + BeforeRestAcc extends UnknownArray = [], |
| 64 | + AfterRestAcc extends UnknownArray = [], |
| 65 | + Result extends UnknownArray = never, |
| 66 | +> = |
| 67 | + keyof TArray & `${number}` extends never |
| 68 | + // Enters this branch, if `TArray` is empty (e.g., `[]`), |
| 69 | + // or `TArray` contains no non-rest elements preceding the rest element (e.g., `[...string[]]` or `[...string[], string]`). |
| 70 | + ? TArray extends readonly [...infer Rest, infer Last] |
| 71 | + ? _ArrayReverse<Rest, BeforeRestAcc, [...AfterRestAcc, Last], Result> // Accumulate elements that are present after the rest element in reverse order. |
| 72 | + : Result | [...AfterRestAcc, ...TArray, ...BeforeRestAcc] // Add the rest element between the accumulated elements. |
| 73 | + : TArray extends readonly [(infer First)?, ...infer Rest] |
| 74 | + ? IsOptionalKeyOf<TArray, '0'> extends true |
| 75 | + ? _ArrayReverse< |
| 76 | + Rest, |
| 77 | + [First | (If<IsExactOptionalPropertyTypesEnabled, never, undefined>), ...BeforeRestAcc], // Add `| undefined` for optional elements, if `exactOptionalPropertyTypes` is disabled. |
| 78 | + AfterRestAcc, |
| 79 | + Result | BeforeRestAcc |
| 80 | + > |
| 81 | + : _ArrayReverse<Rest, [First, ...BeforeRestAcc], AfterRestAcc, Result> |
| 82 | + : never; // Should never happen, since `readonly [(infer First)?, ...infer Rest]` is a top-type for arrays. |
| 83 | + |
| 84 | +export {}; |
0 commit comments