Prerequisites
- Expert knowledge of conditional types and template literal types ๐
- Deep understanding of recursive type patterns and infer keyword โก
- Experience with advanced type-level programming techniques ๐ป
What you'll learn
- Implement complex array algorithms at the type level ๐ฏ
- Build tuple transformation and validation systems ๐๏ธ
- Create compile-time list processors and array utilities ๐
- Apply advanced array manipulation to real-world problems โจ
๐ฏ Introduction
Welcome to the data structure laboratory of TypeScriptโs type system! ๐ข This tutorial explores the fascinating world of type-level array and tuple manipulations, where youโll learn to build sophisticated list processing algorithms using only TypeScriptโs type features.
Youโll discover how to implement complex array operations like mapping, filtering, reducing, and transforming entirely at compile time. Whether youโre building data validation pipelines ๐, creating type-safe array utilities ๐ ๏ธ, or implementing advanced functional programming patterns ๐งฎ, type-level array operations provide incredible power for compile-time list processing.
By the end of this tutorial, youโll be crafting array algorithms that run during compilation and building list processors that guarantee correctness at the type level! Letโs manipulate some tuples! ๐ง
๐ Tuple Fundamentals and Array Types
๐ค Understanding Tuples vs Arrays
In TypeScriptโs type system, tuples are fixed-length arrays with known element types, making them perfect for type-level manipulation:
// ๐ Basic tuple types
type EmptyTuple = [];
type SingleElement = [string];
type Pair = [number, string];
type Triple = [boolean, number, string];
// ๐ฏ Array vs tuple differences
type StringArray = string[]; // Any number of strings
type StringTuple = [string, string]; // Exactly 2 strings
// โจ Tuple with known length
type FixedArray = [1, 2, 3, 4, 5];
type ArrayLength = FixedArray['length']; // 5
// ๐ Mixed type tuples
type MixedTuple = [string, number, boolean, symbol];
type FirstElement = MixedTuple[0]; // string
type SecondElement = MixedTuple[1]; // number
// ๐งช Tuple examples
type TupleTest1 = EmptyTuple['length']; // 0
type TupleTest2 = Pair[0]; // number
type TupleTest3 = Triple[2]; // string
๐๏ธ Tuple Construction and Destructuring
// ๐ฏ Head and tail operations
type Head<T extends readonly unknown[]> =
T extends readonly [infer H, ...unknown[]] ? H : never;
type Tail<T extends readonly unknown[]> =
T extends readonly [unknown, ...infer Rest] ? Rest : never;
type Last<T extends readonly unknown[]> =
T extends readonly [...unknown[], infer L] ? L : never;
type Init<T extends readonly unknown[]> =
T extends readonly [...infer Rest, unknown] ? Rest : never;
// ๐ Tuple access examples
type HeadTest = Head<[1, 2, 3, 4]>; // 1
type TailTest = Tail<[1, 2, 3, 4]>; // [2, 3, 4]
type LastTest = Last<[1, 2, 3, 4]>; // 4
type InitTest = Init<[1, 2, 3, 4]>; // [1, 2, 3]
// ๐ Tuple construction utilities
type Prepend<T, U extends readonly unknown[]> = [T, ...U];
type Append<T extends readonly unknown[], U> = [...T, U];
type PrependTest = Prepend<0, [1, 2, 3]>; // [0, 1, 2, 3]
type AppendTest = Append<[1, 2, 3], 4>; // [1, 2, 3, 4]
// ๐จ Tuple concatenation
type Concat<T extends readonly unknown[], U extends readonly unknown[]> = [...T, ...U];
type ConcatTest = Concat<[1, 2], [3, 4]>; // [1, 2, 3, 4]
// ๐ Tuple repetition
type Repeat<T, N extends number, Acc extends unknown[] = []> =
Acc['length'] extends N ? Acc : Repeat<T, N, [...Acc, T]>;
type RepeatTest = Repeat<"x", 3>; // ["x", "x", "x"]
๐งฎ Tuple Length and Index Operations
// ๐ Length utilities
type Length<T extends readonly unknown[]> = T['length'];
type IsEmpty<T extends readonly unknown[]> = T extends readonly [] ? true : false;
type HasLength<T extends readonly unknown[], N extends number> =
T['length'] extends N ? true : false;
// โ
Length examples
type LengthTest = Length<[1, 2, 3]>; // 3
type EmptyTest = IsEmpty<[]>; // true
type HasLengthTest = HasLength<[1, 2], 2>; // true
// ๐ฏ Index validation and access
type IsValidIndex<T extends readonly unknown[], I extends number> =
I extends keyof T ? true : false;
type At<T extends readonly unknown[], I extends number> =
I extends keyof T ? T[I] : never;
type SafeAt<T extends readonly unknown[], I extends number> =
IsValidIndex<T, I> extends true ? T[I] : undefined;
// ๐ Index access examples
type AtTest1 = At<[10, 20, 30], 1>; // 20
type AtTest2 = At<[10, 20, 30], 5>; // never
type SafeAtTest = SafeAt<[10, 20, 30], 5>; // undefined
// ๐ Index range utilities
type Indices<T extends readonly unknown[]> = {
[K in keyof T]: K
}[number];
type IndicesTest = Indices<["a", "b", "c"]>; // 0 | 1 | 2
// ๐ Index transformation
type IndexPairs<T extends readonly unknown[]> = {
[K in keyof T]: [K, T[K]]
}[number];
type IndexPairsTest = IndexPairs<["x", "y"]>; // [0, "x"] | [1, "y"]
๐ Array Transformation Operations
๐ฏ Map Operation at Type Level
// ๐จ Type-level map implementation
type Map<T extends readonly unknown[], F> = {
[K in keyof T]: F extends (...args: any[]) => any
? F extends (arg: T[K]) => infer R
? R
: never
: F
};
// ๐ String transformation mapper
type StringToLength<S> = S extends string ? S['length'] : never;
type StringToUpper<S> = S extends string ? Uppercase<S> : never;
type MapLengthTest = Map<["hi", "hello", "world"], StringToLength<any>>;
// [2, 5, 5]
type MapUpperTest = Map<["hi", "hello"], StringToUpper<any>>;
// ["HI", "HELLO"]
// ๐ฏ Number transformation mapper
type Double<N> = N extends number ? [N, N] : never;
type ToString<N> = N extends number ? `${N}` : never;
type MapDoubleTest = Map<[1, 2, 3], Double<any>>;
// [[1, 1], [2, 2], [3, 3]]
type MapStringTest = Map<[1, 2, 3], ToString<any>>;
// ["1", "2", "3"]
// ๐ Complex object mapping
type AddId<T> = T & { id: string };
type WrapInArray<T> = [T];
type MapAddIdTest = Map<[{ name: "John" }, { name: "Jane" }], AddId<any>>;
// [{ name: "John"; id: string }, { name: "Jane"; id: string }]
// ๐จ Conditional mapping
type MapIfString<T> = T extends string ? Uppercase<T> : T;
type ConditionalMapTest = Map<["hello", 42, "world"], MapIfString<any>>;
// ["HELLO", 42, "WORLD"]
// ๐ Recursive deep mapping
type DeepMap<T, F> = T extends readonly (infer U)[]
? Map<T, F>
: T extends readonly unknown[]
? { [K in keyof T]: DeepMap<T[K], F> }
: F extends (...args: any[]) => any
? F extends (arg: T) => infer R
? R
: T
: T;
type DeepMapTest = DeepMap<[["a", "b"], ["c", "d"]], StringToUpper<any>>;
// [["A", "B"], ["C", "D"]]
๐ Filter Operation at Type Level
// ๐ฏ Type-level filter implementation
type Filter<T extends readonly unknown[], F> = T extends readonly [infer First, ...infer Rest]
? F extends (arg: First) => any
? F extends (arg: First) => true
? [First, ...Filter<Rest, F>]
: Filter<Rest, F>
: F extends true
? [First, ...Filter<Rest, F>]
: Filter<Rest, F>
: [];
// ๐ String filters
type IsString<T> = T extends string ? true : false;
type IsLongString<T> = T extends string
? T['length'] extends 0 | 1 | 2 | 3 | 4 ? false : true
: false;
type FilterStringsTest = Filter<[1, "hello", 2, "world", true], IsString<any>>;
// ["hello", "world"]
type FilterLongStringsTest = Filter<["hi", "hello", "a", "world"], IsLongString<any>>;
// ["hello", "world"]
// ๐ฏ Number filters
type IsEven<N> = N extends number
? `${N}` extends `${string}${0 | 2 | 4 | 6 | 8}` ? true : false
: false;
type IsPositive<N> = N extends number
? `${N}` extends `-${string}` ? false : true
: false;
type FilterEvenTest = Filter<[1, 2, 3, 4, 5, 6], IsEven<any>>;
// [2, 4, 6]
type FilterPositiveTest = Filter<[-1, 2, -3, 4], IsPositive<any>>;
// [2, 4]
// ๐ Object property filters
type HasProperty<T, K extends PropertyKey> = T extends Record<K, any> ? true : false;
type HasStringProperty<T> = T extends { [K in keyof T]: string } ? true : false;
type FilterWithName = Filter<
[{ name: "John" }, { age: 30 }, { name: "Jane", age: 25 }],
HasProperty<any, "name">
>;
// [{ name: "John" }, { name: "Jane", age: 25 }]
// ๐จ Complex filtering with multiple conditions
type IsStringAndLong<T> = T extends string
? T['length'] extends 0 | 1 | 2 | 3 ? false : true
: false;
type ComplexFilterTest = Filter<
["hi", "hello", 42, "world", "a"],
IsStringAndLong<any>
>;
// ["hello", "world"]
// ๐ Negation filter
type Not<F> = F extends true ? false : true;
type FilterNotStringsTest = Filter<[1, "hello", 2, "world"], Not<IsString<any>>>;
// [1, 2]
๐งฎ Reduce Operation at Type Level
// ๐ฏ Type-level reduce implementation
type Reduce<
T extends readonly unknown[],
Reducer,
Initial = never,
Acc = Initial> = T extends readonly [infer First, ...infer Rest]
? Reduce<Rest, Reducer, Initial,
Reducer extends (acc: Acc, current: First) => infer Result
? Result
: Acc>
: Acc;
// ๐งฎ Sum reducer
type Sum<Acc, Current> = Acc extends number
? Current extends number
? Add<Acc, Current>
: Acc
: Current extends number
? Current
: 0;
// Helper for addition (simplified for small numbers)
type Add<A extends number, B extends number> =
A extends 0 ? B :
B extends 0 ? A :
A extends 1 ? B extends 1 ? 2 : B extends 2 ? 3 : B extends 3 ? 4 : never :
A extends 2 ? B extends 1 ? 3 : B extends 2 ? 4 : B extends 3 ? 5 : never :
A extends 3 ? B extends 1 ? 4 : B extends 2 ? 5 : B extends 3 ? 6 : never :
never;
type SumTest = Reduce<[1, 2, 3], Sum<any, any>, 0>; // 6
// ๐ Concatenation reducer
type Concat<Acc, Current> = Acc extends string
? Current extends string
? `${Acc}${Current}`
: Acc
: Current extends string
? Current
: "";
type ConcatTest = Reduce<["Hello", " ", "World"], Concat<any, any>, "">;
// "Hello World"
// ๐ Array accumulation reducer
type ArrayAccumulator<Acc, Current> = Acc extends readonly unknown[]
? [...Acc, Current]
: [Current];
type AccumulateTest = Reduce<[1, 2, 3], ArrayAccumulator<any, any>, []>;
// [1, 2, 3]
// ๐ฏ Object accumulation reducer
type ObjectAccumulator<Acc, Current> = Acc extends Record<string, unknown>
? Current extends Record<string, unknown>
? Acc & Current
: Acc
: Current extends Record<string, unknown>
? Current
: {};
type ObjectTest = Reduce<
[{ a: 1 }, { b: 2 }, { c: 3 }],
ObjectAccumulator<any, any>,
{}
>;
// { a: 1; b: 2; c: 3 }
// ๐ Min/Max reducers
type Min<Acc, Current> = Acc extends number
? Current extends number
? Current extends 0 ? 0 :
Current extends 1 ? Acc extends 0 ? 0 : 1 :
Current extends 2 ? Acc extends 0 | 1 ? Acc : 2 :
Current extends 3 ? Acc extends 0 | 1 | 2 ? Acc : 3 :
Acc
: Acc
: Current;
type MinTest = Reduce<[3, 1, 4, 1, 5], Min<any, any>, never>;
// 1
// ๐ Count reducer
type Counter<Acc, Current> = Acc extends number ? Add<Acc, 1> : 1;
type CountTest = Reduce<["a", "b", "c"], Counter<any, any>, 0>;
// 3
๐ Array Search and Query Operations
๐ฏ Find and Search Operations
// ๐ Find first element matching predicate
type Find<T extends readonly unknown[], Predicate> = T extends readonly [infer First, ...infer Rest]
? Predicate extends (arg: First) => true
? First
: Find<Rest, Predicate>
: never;
// ๐ Find index of element
type FindIndex<
T extends readonly unknown[],
Predicate,
Index extends number = 0> = T extends readonly [infer First, ...infer Rest]
? Predicate extends (arg: First) => true
? Index
: FindIndex<Rest, Predicate, Add<Index, 1>>
: never;
// ๐ฏ Find examples
type FindStringTest = Find<[1, "hello", 2, "world"], IsString<any>>;
// "hello"
type FindIndexTest = FindIndex<[1, "hello", 2, "world"], IsString<any>>;
// 1
// ๐ Includes operation
type Includes<T extends readonly unknown[], U> = T extends readonly [infer First, ...infer Rest]
? First extends U
? true
: Includes<Rest, U>
: false;
type IncludesTest1 = Includes<[1, 2, 3], 2>; // true
type IncludesTest2 = Includes<[1, 2, 3], 4>; // false
// ๐ฏ Every and Some operations
type Every<T extends readonly unknown[], Predicate> = T extends readonly [infer First, ...infer Rest]
? Predicate extends (arg: First) => true
? Every<Rest, Predicate>
: false
: true;
type Some<T extends readonly unknown[], Predicate> = T extends readonly [infer First, ...infer Rest]
? Predicate extends (arg: First) => true
? true
: Some<Rest, Predicate>
: false;
// โ
Every/Some examples
type EveryStringTest = Every<["a", "b", "c"], IsString<any>>; // true
type EveryNumberTest = Every<["a", 1, "c"], IsString<any>>; // false
type SomeStringTest = Some<[1, "hello", 2], IsString<any>>; // true
type SomeNumberTest = Some<["a", "b", "c"], IsString<any>>; // true
// ๐ Count occurrences
type Count<T extends readonly unknown[], U, Acc extends number = 0> = T extends readonly [infer First, ...infer Rest]
? First extends U
? Count<Rest, U, Add<Acc, 1>>
: Count<Rest, U, Acc>
: Acc;
type CountTest = Count<[1, 2, 1, 3, 1], 1>; // 3
// ๐ฏ Find all indices
type FindAllIndices<
T extends readonly unknown[],
U,
Acc extends number[] = [],
Index extends number = 0> = T extends readonly [infer First, ...infer Rest]
? First extends U
? FindAllIndices<Rest, U, [...Acc, Index], Add<Index, 1>>
: FindAllIndices<Rest, U, Acc, Add<Index, 1>>
: Acc;
type FindAllTest = FindAllIndices<[1, 2, 1, 3, 1], 1>;
// [0, 2, 4]
๐งฉ Array Comparison and Set Operations
// ๐ฏ Array equality
type Equal<T extends readonly unknown[], U extends readonly unknown[]> =
T extends readonly [infer TFirst, ...infer TRest]
? U extends readonly [infer UFirst, ...infer URest]
? TFirst extends UFirst
? UFirst extends TFirst
? Equal<TRest, URest>
: false
: false
: false
: U extends readonly []
? true
: false;
type EqualTest1 = Equal<[1, 2, 3], [1, 2, 3]>; // true
type EqualTest2 = Equal<[1, 2, 3], [1, 2, 4]>; // false
// ๐ Remove duplicates (unique)
type Unique<T extends readonly unknown[], Acc extends readonly unknown[] = []> =
T extends readonly [infer First, ...infer Rest]
? Includes<Acc, First> extends true
? Unique<Rest, Acc>
: Unique<Rest, [...Acc, First]>
: Acc;
type UniqueTest = Unique<[1, 2, 2, 3, 1, 4]>; // [1, 2, 3, 4]
// ๐ Union of arrays
type Union<T extends readonly unknown[], U extends readonly unknown[]> =
Unique<[...T, ...U]>;
type UnionTest = Union<[1, 2, 3], [3, 4, 5]>; // [1, 2, 3, 4, 5]
// ๐ฏ Intersection of arrays
type Intersection<T extends readonly unknown[], U extends readonly unknown[]> =
Filter<T, (x: any) => Includes<U, any> extends true ? true : false>;
type IntersectionTest = Intersection<[1, 2, 3, 4], [3, 4, 5, 6]>;
// [3, 4]
// ๐ซ Difference of arrays
type Difference<T extends readonly unknown[], U extends readonly unknown[]> =
Filter<T, (x: any) => Includes<U, any> extends true ? false : true>;
type DifferenceTest = Difference<[1, 2, 3, 4], [3, 4, 5, 6]>;
// [1, 2]
// ๐ Symmetric difference
type SymmetricDifference<T extends readonly unknown[], U extends readonly unknown[]> =
Union<Difference<T, U>, Difference<U, T>>;
type SymDiffTest = SymmetricDifference<[1, 2, 3], [3, 4, 5]>;
// [1, 2, 4, 5]
// โ
Subset checking
type IsSubset<T extends readonly unknown[], U extends readonly unknown[]> =
Every<T, (x: any) => Includes<U, any>>;
type SubsetTest1 = IsSubset<[1, 2], [1, 2, 3, 4]>; // true
type SubsetTest2 = IsSubset<[1, 5], [1, 2, 3, 4]>; // false
๐จ Advanced Array Algorithms
๐ Sorting and Ordering
// ๐ฏ Insertion sort (simplified for small arrays)
type InsertionSort<T extends readonly unknown[]> = T extends readonly [infer First, ...infer Rest]
? Insert<First, InsertionSort<Rest>>
: [];
type Insert<X, Sorted extends readonly unknown[]> = Sorted extends readonly [infer First, ...infer Rest]
? X extends number
? First extends number
? X extends 0 ? [X, ...Sorted] :
X extends 1 ? First extends 0 ? [First, X, ...Rest] : [X, ...Sorted] :
X extends 2 ? First extends 0 | 1 ? [First, ...Insert<X, Rest>] : [X, ...Sorted] :
[X, ...Sorted] // Simplified for demonstration
: [X, ...Sorted]
: [X, ...Sorted]
: [X];
type SortTest = InsertionSort<[3, 1, 4, 1, 5]>; // Simplified result
// ๐ Reverse operation
type Reverse<T extends readonly unknown[], Acc extends readonly unknown[] = []> =
T extends readonly [infer First, ...infer Rest]
? Reverse<Rest, [First, ...Acc]>
: Acc;
type ReverseTest = Reverse<[1, 2, 3, 4]>; // [4, 3, 2, 1]
// ๐ฏ Rotate array
type RotateLeft<T extends readonly unknown[], N extends number = 1> =
N extends 0 ? T :
T extends readonly [infer First, ...infer Rest]
? RotateLeft<[...Rest, First], Subtract<N, 1>>
: T;
// Helper for subtraction (simplified)
type Subtract<A extends number, B extends number> =
A extends 0 ? 0 :
B extends 0 ? A :
A extends 1 ? B extends 1 ? 0 : never :
A extends 2 ? B extends 1 ? 1 : B extends 2 ? 0 : never :
A extends 3 ? B extends 1 ? 2 : B extends 2 ? 1 : B extends 3 ? 0 : never :
never;
type RotateTest = RotateLeft<[1, 2, 3, 4], 2>; // [3, 4, 1, 2]
// ๐ Shuffle indices (deterministic permutation)
type SwapAt<
T extends readonly unknown[],
I extends number,
J extends number> = {
[K in keyof T]: K extends `${I}`
? T[J]
: K extends `${J}`
? T[I]
: T[K]
};
type SwapTest = SwapAt<["a", "b", "c", "d"], 1, 3>;
// ["a", "d", "c", "b"]
๐งฉ Matrix and 2D Array Operations
// ๐ฏ Matrix type definitions
type Matrix<T> = readonly (readonly T[])[];
type Vector<T> = readonly T[];
// ๐ Matrix dimensions
type Rows<M extends Matrix<unknown>> = M['length'];
type Cols<M extends Matrix<unknown>> = M extends readonly [infer FirstRow, ...unknown[]]
? FirstRow extends readonly unknown[]
? FirstRow['length']
: 0
: 0;
// ๐ Matrix transpose
type Transpose<M extends Matrix<unknown>> = M extends readonly [infer FirstRow, ...infer RestRows]
? FirstRow extends readonly unknown[]
? RestRows extends Matrix<unknown>
? {
[K in keyof FirstRow]: [FirstRow[K], ...GetColumn<RestRows, K>]
}
: { [K in keyof FirstRow]: [FirstRow[K]] }
: []
: [];
type GetColumn<M extends Matrix<unknown>, Col extends PropertyKey> = {
[K in keyof M]: M[K] extends readonly unknown[]
? Col extends keyof M[K]
? M[K][Col]
: never
: never
};
// โ
Matrix transpose example
type TransposeTest = Transpose<[
[1, 2, 3],
[4, 5, 6]
]>; // [[1, 4], [2, 5], [3, 6]]
// ๐ฏ Matrix row and column access
type GetRow<M extends Matrix<unknown>, Row extends keyof M> = M[Row];
type GetCell<M extends Matrix<unknown>, Row extends keyof M, Col extends PropertyKey> =
M[Row] extends readonly unknown[]
? Col extends keyof M[Row]
? M[Row][Col]
: never
: never;
// ๐ Flatten matrix
type Flatten<M extends Matrix<unknown>, Acc extends readonly unknown[] = []> =
M extends readonly [infer FirstRow, ...infer RestRows]
? FirstRow extends readonly unknown[]
? RestRows extends Matrix<unknown>
? Flatten<RestRows, [...Acc, ...FirstRow]>
: [...Acc, ...FirstRow]
: Acc
: Acc;
type FlattenTest = Flatten<[[1, 2], [3, 4], [5, 6]]>;
// [1, 2, 3, 4, 5, 6]
// ๐ Reshape flat array to matrix
type Reshape<
T extends readonly unknown[],
Rows extends number,
Cols extends number> = Length<T> extends Multiply<Rows, Cols>
? ReshapeHelper<T, Cols>
: never;
type ReshapeHelper<
T extends readonly unknown[],
Cols extends number,
Acc extends Matrix<unknown> = []
> = T extends readonly []
? Acc
: Take<T, Cols> extends infer Row
? Row extends readonly unknown[]
? Drop<T, Cols> extends infer Rest
? Rest extends readonly unknown[]
? ReshapeHelper<Rest, Cols, [...Acc, Row]>
: Acc
: Acc
: Acc
: Acc;
// Helper functions for reshape
type Take<T extends readonly unknown[], N extends number, Acc extends readonly unknown[] = []> =
Acc['length'] extends N ? Acc :
T extends readonly [infer First, ...infer Rest]
? Take<Rest, N, [...Acc, First]>
: Acc;
type Drop<T extends readonly unknown[], N extends number> =
N extends 0 ? T :
T extends readonly [unknown, ...infer Rest]
? Drop<Rest, Subtract<N, 1>>
: [];
// Simplified multiply for small numbers
type Multiply<A extends number, B extends number> =
A extends 0 ? 0 :
A extends 1 ? B :
A extends 2 ? B extends 1 ? 2 : B extends 2 ? 4 : B extends 3 ? 6 : never :
A extends 3 ? B extends 1 ? 3 : B extends 2 ? 6 : B extends 3 ? 9 : never :
never;
๐ฏ Sliding Window and Chunking
// ๐ช Sliding window operation
type SlidingWindow<
T extends readonly unknown[],
Size extends number,
Acc extends readonly (readonly unknown[])[] = []
> = Take<T, Size> extends infer Window
? Window extends readonly unknown[]
? Length<Window> extends Size
? Drop<T, 1> extends infer Rest
? Rest extends readonly unknown[]
? Length<Rest> extends 0
? [...Acc, Window]
: SlidingWindow<Rest, Size, [...Acc, Window]>
: [...Acc, Window]
: [...Acc, Window]
: Acc
: Acc
: Acc;
type SlidingWindowTest = SlidingWindow<[1, 2, 3, 4, 5], 3>;
// [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
// ๐งฉ Chunk array into fixed-size groups
type Chunk<
T extends readonly unknown[],
Size extends number,
Acc extends readonly (readonly unknown[])[] = []
> = T extends readonly []
? Acc
: Take<T, Size> extends infer Group
? Group extends readonly unknown[]
? Drop<T, Size> extends infer Rest
? Rest extends readonly unknown[]
? Chunk<Rest, Size, [...Acc, Group]>
: [...Acc, Group]
: [...Acc, Group]
: Acc
: Acc;
type ChunkTest = Chunk<[1, 2, 3, 4, 5, 6, 7], 3>;
// [[1, 2, 3], [4, 5, 6], [7]]
// ๐ฏ Partition array by predicate
type Partition<T extends readonly unknown[], Predicate> = [
Filter<T, Predicate>,
Filter<T, Not<Predicate>>
];
type PartitionTest = Partition<[1, "a", 2, "b", 3], IsString<any>>;
// [["a", "b"], [1, 2, 3]]
// ๐ Group by key function
type GroupBy<T extends readonly unknown[], KeyFn> = T extends readonly [infer First, ...infer Rest]
? KeyFn extends (arg: First) => infer Key
? {
[K in Key]: Filter<T, (x: any) => KeyFn extends (arg: any) => K ? true : false>
} & (Rest extends readonly unknown[] ? GroupBy<Rest, KeyFn> : {})
: {}
: {};
// Example: Group by string length
type GroupByLength<S> = S extends string ? S['length'] : never;
type GroupByTest = GroupBy<["hi", "hello", "a", "world"], GroupByLength<any>>;
// Complex result grouping strings by length
// ๐ Zip arrays together
type Zip<T extends readonly unknown[], U extends readonly unknown[]> = T extends readonly [infer TFirst, ...infer TRest]
? U extends readonly [infer UFirst, ...infer URest]
? [[TFirst, UFirst], ...Zip<TRest, URest>]
: []
: [];
type ZipTest = Zip<[1, 2, 3], ["a", "b", "c"]>;
// [[1, "a"], [2, "b"], [3, "c"]]
// ๐จ Zip with index
type ZipWithIndex<T extends readonly unknown[], Index extends number = 0> = T extends readonly [infer First, ...infer Rest]
? [[Index, First], ...ZipWithIndex<Rest, Add<Index, 1>>]
: [];
type ZipWithIndexTest = ZipWithIndex<["a", "b", "c"]>;
// [[0, "a"], [1, "b"], [2, "c"]]
๐ก๏ธ Type-Safe Array Validation and Utilities
๐ Array Shape Validation
// ๐ฏ Array shape validators
type IsHomogeneous<T extends readonly unknown[]> = T extends readonly []
? true
: T extends readonly [infer First, ...infer Rest]
? Every<Rest, (x: any) => x extends First ? true : false>
: false;
type IsFixed<T extends readonly unknown[], L extends number> =
T['length'] extends L ? true : false;
type IsNonEmpty<T extends readonly unknown[]> =
T extends readonly [] ? false : true;
// โ
Shape validation examples
type HomogeneousTest1 = IsHomogeneous<[1, 2, 3]>; // true
type HomogeneousTest2 = IsHomogeneous<[1, "a", 3]>; // false
type FixedTest = IsFixed<[1, 2, 3], 3>; // true
type NonEmptyTest = IsNonEmpty<[]>; // false
// ๐ก๏ธ Type-safe array builders
type SafeArray<T, L extends number> =
readonly T[] & { length: L };
type SafeTuple<T extends readonly unknown[]> =
IsHomogeneous<T> extends true ? T : never;
type SafeNonEmpty<T extends readonly unknown[]> =
IsNonEmpty<T> extends true ? T : never;
// ๐ฏ Array bounds checking
type InBounds<T extends readonly unknown[], I extends number> =
IsValidIndex<T, I>;
type SafeAccess<T extends readonly unknown[], I extends number> =
InBounds<T, I> extends true ? T[I] : never;
// ๐ Range validation
type InRange<N extends number, Min extends number, Max extends number> =
N extends Min ? true :
N extends Max ? true :
// Simplified range check
N extends 0 ? Min extends 0 ? true : false :
N extends 1 ? Min extends 0 | 1 ? Max extends 1 | 2 | 3 | 4 | 5 ? true : false : false :
boolean;
type RangeTest = InRange<3, 1, 5>; // true
// ๐ Array content validation
type AllStrings<T extends readonly unknown[]> =
Every<T, IsString<any>>;
type AllNumbers<T extends readonly unknown[]> =
Every<T, (x: any) => x extends number ? true : false>;
type AllOfType<T extends readonly unknown[], U> =
Every<T, (x: any) => x extends U ? true : false>;
// โ
Content validation examples
type AllStringsTest = AllStrings<["a", "b", "c"]>; // true
type AllNumbersTest = AllNumbers<[1, 2, "3"]>; // false
type AllBoolTest = AllOfType<[true, false, true], boolean>; // true
๐จ Advanced Array Utilities
// ๐ Array interleaving
type Interleave<T extends readonly unknown[], U extends readonly unknown[]> =
T extends readonly [infer TFirst, ...infer TRest]
? U extends readonly [infer UFirst, ...infer URest]
? [TFirst, UFirst, ...Interleave<TRest, URest>]
: T
: U;
type InterleaveTest = Interleave<[1, 2, 3], ["a", "b", "c"]>;
// [1, "a", 2, "b", 3, "c"]
// ๐ฏ Cartesian product
type CartesianProduct<T extends readonly unknown[], U extends readonly unknown[]> =
T extends readonly [infer TFirst, ...infer TRest]
? [
...Map<U, (x: any) => [TFirst, any]>,
...(TRest extends readonly unknown[] ? CartesianProduct<TRest, U> : [])
]
: [];
type CartesianTest = CartesianProduct<[1, 2], ["a", "b"]>;
// [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
// ๐ Permutations (simplified for small arrays)
type Permutations<T extends readonly unknown[]> = T extends readonly []
? [[]]
: T extends readonly [infer First, ...infer Rest]
? Rest extends readonly unknown[]
? InsertAtAllPositions<First, Permutations<Rest>>
: []
: [];
type InsertAtAllPositions<
X,
Perms extends readonly (readonly unknown[])[]
> = Perms extends readonly [infer FirstPerm, ...infer RestPerms]
? FirstPerm extends readonly unknown[]
? RestPerms extends readonly (readonly unknown[])[]
? [
...InsertAtPositions<X, FirstPerm>,
...InsertAtAllPositions<X, RestPerms>
]
: InsertAtPositions<X, FirstPerm>
: []
: [];
type InsertAtPositions<X, T extends readonly unknown[], Index extends number = 0> =
Index extends T['length']
? [[...T, X]]
: [
[...Take<T, Index>, X, ...Drop<T, Index>],
...InsertAtPositions<X, T, Add<Index, 1>>
];
type PermTest = Permutations<[1, 2]>; // [[1, 2], [2, 1]]
// ๐งฎ Array statistics
type Min<T extends readonly number[]> = Reduce<T, Min<any, any>, never>;
type Max<T extends readonly number[]> = Reduce<T, Max<any, any>, never>;
type Sum<T extends readonly number[]> = Reduce<T, Sum<any, any>, 0>;
// ๐ฏ Array comparison utilities
type IsPrefix<Prefix extends readonly unknown[], T extends readonly unknown[]> =
Prefix extends readonly []
? true
: Prefix extends readonly [infer PFirst, ...infer PRest]
? T extends readonly [infer TFirst, ...infer TRest]
? PFirst extends TFirst
? TFirst extends PFirst
? IsPrefix<PRest, TRest>
: false
: false
: false
: false;
type IsSuffix<Suffix extends readonly unknown[], T extends readonly unknown[]> =
IsPrefix<Suffix, Reverse<T>>;
type PrefixTest = IsPrefix<[1, 2], [1, 2, 3, 4]>; // true
type SuffixTest = IsSuffix<[3, 4], [1, 2, 3, 4]>; // true
// ๐ Array subsequence checking
type IsSubsequence<Sub extends readonly unknown[], T extends readonly unknown[]> =
Sub extends readonly []
? true
: Sub extends readonly [infer SubFirst, ...infer SubRest]
? T extends readonly [infer TFirst, ...infer TRest]
? SubFirst extends TFirst
? TFirst extends SubFirst
? IsSubsequence<SubRest, TRest>
: IsSubsequence<Sub, TRest>
: IsSubsequence<Sub, TRest>
: false
: false;
type SubsequenceTest = IsSubsequence<[1, 3, 5], [1, 2, 3, 4, 5]>; // true
๐ Key Takeaways
Youโve mastered the array manipulation capabilities of TypeScriptโs type system! Hereโs what you now command:
- โ Tuple fundamentals including construction, destructuring, and access ๐ช
- โ Array transformations with map, filter, and reduce operations ๐ก๏ธ
- โ Search and query operations for finding and analyzing elements ๐ฏ
- โ Advanced algorithms including sorting, matrix operations, and windowing ๐
- โ Type-safe validation and array shape checking ๐
- โ Complex utilities for permutations, products, and statistical operations โจ
- โ Real-world applications in data processing and validation pipelines ๐
Remember: Type-level array operations enable you to build incredibly powerful compile-time data processors! ๐ค
๐ค Next Steps
Congratulations! ๐ Youโve become a master of array manipulation in TypeScriptโs type system!
Hereโs what to do next:
- ๐ป Build data validation pipelines with compile-time array processing
- ๐๏ธ Create type-safe array utilities and functional programming patterns
- ๐ Move on to our next tutorial: Type Predicates - User-Defined Type Guards
- ๐ Implement matrix operations and linear algebra in the type system
- ๐ Explore advanced functional programming patterns with type-level arrays
- ๐ฏ Build intelligent data transformation and ETL systems
- ๐ Push the boundaries of compile-time data processing
Remember: You now possess the power to manipulate arrays and data structures entirely at the type level! Use this knowledge to build incredibly safe and intelligent data systems. ๐
Happy array manipulating! ๐๐ขโจ