Array
The array category covers types that work on Array<T> and, in most cases, on tuples too.
Types that only make sense on a fixed-length tuple live in tuple.
Many of these types are also exported under the ArrayPlus namespace,
which holds the array-specific variant when a tuple-specific one also exists.
Sources: packages/type-plus/src/array.
IsArray / IsNotArray
Section titled “IsArray / IsNotArray”type IsArray<T, $O extends $StrictOptions<$O, IsArray.$Options> = {}>type IsNotArray<T, $O extends $StrictOptions<$O, IsNotArray.$Options> = {}>type R = IsArray<number[]> // truetype R = IsArray<[1]> // truetype R = IsArray<number> // false
type R = IsNotArray<number> // trueThe check is loose: a tuple is an array, the same way a string literal is a string.
Pass exact to narrow the check to Array<T> only:
type R = IsArray<[1], { exact: true }> // falsetype R = IsArray<number[], { exact: true }> // trueBoth accept type branching options:
type R = IsArray<number[], { selection: 'filter' }> // number[]type R = IsArray<number, { selection: 'filter' }> // nevertype R = IsArray<number[] | 1, { distributive: false }> // falseHead and Last
Section titled “Head and Last”type Head<T extends readonly unknown[], $O extends $StrictOptions<$O, Head.$Options> = {}>type Last<T extends readonly unknown[], $O extends $StrictOptions<$O, Last.$Options> = {}>type R = Head<[1, 2, 3]> // 1type R = Last<[1, 2, 3]> // 3type R = Head<string[]> // stringtype R = Last<[]> // neverBoth take $O['$never'] and $O['$emptyTuple'] to override the never and [] cases.
At and IndexAt
Section titled “At and IndexAt”type At<A extends readonly unknown[], N extends number, $O extends $StrictOptions<$O, At.$Options> = {}>type IndexAt<A extends readonly unknown[], N extends number, $O extends $StrictOptions<$O, IndexAt.$Options> = {}>type IsIndexOutOfBound<A extends readonly unknown[], N extends number, $O extends $StrictOptions<$O, IsIndexOutOfBound.$Options> = {}>At reads the element type at index N, and like Array.at() supports negative numbers.
IndexAt normalizes the index itself.
type R = At<[1, 2, 3], 2> // 3type R = At<[1, 2, 3], -1> // 3
type R = IndexAt<['a', 'b', 'c'], -2> // 1type R = IndexAt<['a', 'b', 'c'], 3> // 3 (upper bound)
type R = IsIndexOutOfBound<[1], 1> // truetype R = IsIndexOutOfBound<[1], 1, { selection: 'filter' }> // 1type R = IsIndexOutOfBound<[1], 0, { $then: 'yes'; $else: 'no' }> // 'no'IsIndexOutOfBound accepts the full type branching options.
Before 8.0.0 it took Then and Else positionally; move them into { $then, $else }.
IndexAt takes an options object to override each case it can land on:
$O['$never'] when A is never (default never),
$O['$array'] when A is an array rather than a tuple (default N),
$O['$emptyTuple'] when A is [] (default never),
$O['$upperBound'] when N is past the upper bound (default A['length']),
and $O['$lowerBound'] when N is past the lower bound (default 0).
type R = IndexAt<never, 0, { $never: 'n' }> // 'n'type R = IndexAt<string[], 0, { $array: 'a' }> // 'a'type R = IndexAt<[], 0, { $emptyTuple: 'e' }> // 'e'type R = IndexAt<[1], 1, { $upperBound: 'u' }> // 'u'type R = IndexAt<[1], -2, { $lowerBound: 'l' }> // 'l'Before v8 these cases were positional type parameters
(IndexAt<A, N, Fail, Upper, Lower>); move them into the options object under
$emptyTuple, $upperBound and $lowerBound.
type Slice<A extends readonly unknown[], Start extends number = 0, End extends number = A['length']>Slice is the type level Array.prototype.slice(): it gets the section of A from Start up to,
but not including, End. A negative index counts back from the end, and an index out of bounds is
clamped to the boundary. It is also available as ArrayPlus.Slice.
type R = Slice<[1, 2, 3], 1> // [2, 3]type R = Slice<[1, 2, 3], 0, 2> // [1, 2]type R = Slice<[1, 2, 3], -3, -1> // [1, 2]type R = Slice<[1, 2, 3], -5, 5> // [1, 2, 3]type R = Slice<[1, 2, 3], 2, 1> // []On an array, or when Start or End is the wide number or any, the section cannot be known,
and the result is an array of the element type: Slice<string[], 1> is string[].
The result is mutable even when A is readonly, as slice() returns a new array.
A non-integer or never index gets never.
Filter and DropMatch
Section titled “Filter and DropMatch”🗑️ removed in 8.0.0: KeepMatch — use Filter instead.
type Filter<A extends readonly unknown[], Criteria>namespace ArrayPlus { type DropMatch<A extends Readonly<unknown[]>, Criteria> }Filter keeps the entries satisfying Criteria. DropMatch removes them.
type R = Filter<[1, 2, '3'], number> // [1, 2]type R = Filter<Array<string | undefined>, string> // string[]
type R = ArrayPlus.DropMatch<Array<string | undefined>, undefined> // string[]type R = ArrayPlus.DropMatch<Array<string>, string> // never[]DropMatch also takes a type function such as IsObject.$Fn,
and drops the element types it returns true for.
Filter takes one only for a tuple.
type R = ArrayPlus.DropMatch<Array<string | { a: 1 }>, IsObject.$Fn> // string[]ArrayPlus.Filter is the array-only variant, with $O['$never'] and $O['$notArray'].
It does not take a type function.
Finding
Section titled “Finding”type FindFirst<A, Criteria, $O extends $StrictOptions<$O, FindFirst.$Options> = {}>type FindLast<A extends readonly unknown[], Criteria>namespace ArrayPlus { type Find<A, Criteria, $O extends $StrictOptions<$O, Find.$Options> = {}> }type Some<A extends readonly unknown[], Criteria, $O extends $StrictOptions<$O, Some.$Options> = {}>type R = FindFirst<[true, 1, 'x', 3], string> // 'x'type R = FindLast<[true, 123, 'x', 321], number> // 321type R = FindFirst<Array<string>, string> // stringtype R = FindFirst<[true, 1, 'x'], 2> // never
type R = Some<['a', true], boolean> // truetype R = Some<['a', true], boolean, { mode: 'strict' }> // falseFindFirst and ArrayPlus.Find match widened types by default:
FindFirst<Array<number>, 1> is 1 | undefined.
Set $O['widen'] to false, or $O['$widen'] to never, for a purely type-centric result.
ElementMatch<T, Criteria, Options> is the single-element matcher these are built on.
FindFirst, FindLast, ArrayPlus.Find and Some also take a type function
as Criteria. An element matches when the function returns true.
The widen options and Some’s mode do not apply to it.
Pass IsEqual.$Fn<X> to match an element exactly (strict mode).
Some accepts the full type branching options plus its own
mode: 'loose' | 'strict' (default 'loose'). Before 8.0.0, mode was the third positional
parameter, Then and Else the fourth and fifth: Some<A, C, 'strict'> is now
Some<A, C, { mode: 'strict' }>, and Some<A, C, 'loose', Then, Else> is now
Some<A, C, { $then: Then; $else: Else }>.
type R = FindFirst<[1, { a: 1 }, object], IsObject.$Fn<{ exact: true }>> // objecttype R = ArrayPlus.Find<Array<1 | { a: 1 }>, IsObject.$Fn> // { a: 1 }type R = FindLast<[1, 'x', { a: 1 }, 2], IsObject.$Fn> // { a: 1 }type R = FindFirst<[number, 1], IsEqual.$Fn<1>> // 1type R = Some<[1, { a: 1 }], IsObject.$Fn> // truetype R = Some<Array<string | { a: 1 }>, IsObject.$Fn> // booleanReverse, PadStart, SplitAt
Section titled “Reverse, PadStart, SplitAt”🗑️ removed in 8.0.0: Concat and ArrayPlus.Concat — use the spread tuple [...A, ...B] instead.
type Reverse<A extends readonly unknown[]>type PadStart<A extends readonly unknown[], MaxLength extends number, PadWith = unknown>namespace ArrayPlus { type SplitAt<A, Index extends number, DeleteCount extends number = never, Insert extends readonly unknown[] = never> }type R = Reverse<[1, 2, 3]> // [3, 2, 1]
type R = PadStart<[1, 2, 3], 5, 0> // [0, 0, 1, 2, 3]type R = PadStart<[1, 2, 3], 5> // [unknown, unknown, 1, 2, 3]type R = PadStart<number[], 1, string> // [string, ...number[]]
type R = ArrayPlus.SplitAt<[1, 2, 3, 4, 5], 2> // [[1, 2], [3, 4, 5]]type R = ArrayPlus.SplitAt<[1, 2, 3, 4, 5], 2, 2, ['a', 'b']> // [[1, 2, 'a', 'b', 5], [3, 4]]SplitAt accepts negative indexes and clamps an out-of-bound index to the boundary.
Removed aliases
Section titled “Removed aliases”🗑️ removed in 8.0.0: use FindFirst and PadStart instead.
Both were thin aliases kept for the v7 line. Neither was exported from the package entry point in v7, so this only affects deep imports:
| Removed | Replacement |
|---|---|
First<A, Criteria> |
FindFirst<A, Criteria>, ArrayPlus.Find<A, Criteria> |
PadLeft<A, Total, PadWith> |
PadStart<A, MaxLength, PadWith> |
Values and properties of elements
Section titled “Values and properties of elements”type UnionOfValues<A extends readonly unknown[]>type UnionOfProps<A extends readonly Record<any, any>[], P extends KeyTypes>type IntersectOfProps<A extends readonly Record<any, unknown>[], P extends KeyTypes>namespace ArrayPlus { type CommonPropKeys<A extends readonly Record<KeyTypes, unknown>[], Options = ...> }type R = UnionOfValues<[1, 2, 3]> // 1 | 2 | 3type R = UnionOfProps<[{ a: 1 }, { a: 2 }], 'a'> // 1 | 2type R = IntersectOfProps<[{ a: { x: 1 } }, { a: { y: 2 } }], 'a'> // { x: 1 } & { y: 2 }type R = ArrayPlus.CommonPropKeys<Array<{ a: 1; b: 1 } | { a: 1; c: 1 }>> // 'a'🗑️ removed in 8.0.0:
PropUnion— useUnionOfPropsinstead.MapToProp— useIntersectOfPropsinstead.ArrayValue— useUnionOfValuesinstead.
Entries and IsReadonly
Section titled “Entries and IsReadonly”namespace ArrayPlus { type Entries<A extends readonly unknown[]> type IsReadonly<A, $O extends $StrictOptions<$O, IsReadonly.$Options> = {}>}type R = ArrayPlus.Entries<[1, 2, 3]> // [[0, 1], [1, 2], [2, 3]]type R = ArrayPlus.Entries<Array<string | number>> // Array<[number, string | number]>
type R = ArrayPlus.IsReadonly<readonly [1, 2]> // truetype R = ArrayPlus.IsReadonly<[1, 2]> // falsetype R = ArrayPlus.IsReadonly<readonly string[] | number[], { selection: 'filter' }> // readonly string[]IsReadonly takes the full type branching options, including the
$any, $unknown, $never and $void branches, and has IsReadonly.$Fn. A value that is not an
array resolves to $else.
Before 8.0.0 it took the legacy IsReadonly.Options with a $notArray branch; for that, write
IsArray<A, { $then: IsReadonly<A>; $else: X }>.
namespace ArrayPlus { type Join<A extends readonly unknown[], Separator extends string = ','>}The type-level Array.prototype.join. It joins the elements of a tuple into a string. Separator
defaults to ',', and null and undefined become the empty string, as they do at runtime.
type R = ArrayPlus.Join<['a', 'b', 'c']> // 'a,b,c'type R = ArrayPlus.Join<['a', 'b', 'c'], '/'> // 'a/b/c'type R = ArrayPlus.Join<[1, true, null, 2n], '-'> // '1-true--2'type R = ArrayPlus.Join<[]> // ''An array, a tuple with optional or rest elements, or a wide Separator gives string, because the
number of elements or what separates them is unknown. An element with no known string form, such as
an object, becomes string.
type R = ArrayPlus.Join<string[]> // stringIt is the inverse of StringPlus.Split.
Loose array types
Section titled “Loose array types”🗑️ removed in 8.0.0: use IsArray and IsNotArray instead.
LooseArrayType and its variances were a stopgap while ArrayType still did a strict,
tuple-excluding check. IsArray is loose by default, so the stopgap is no longer needed:
| Removed | Replacement |
|---|---|
LooseArrayType<T> |
IsArray<T, { selection: 'filter' }> |
IsLooseArray<T> |
IsArray<T> |
NotLooseArrayType<T> |
IsNotArray<T, { selection: 'filter' }> |
IsNotLooseArray<T> |
IsNotArray<T> |
IsArray also distributes over unions, so the filter form returns only the array members:
type R = IsArray<number[] | 1, { selection: 'filter' }> // number[]Runtime functions
Section titled “Runtime functions”| Function | Description |
|---|---|
literalArray(...entries) |
Returns an array whose items are restricted to the provided literals. |
reduceWhile(predicate, callbackfn, initialValue, array) |
reduce() with a predicate for early termination. |