typescript / expert
Snippet
Type-Safe Variadic Composition Pipeline using Infer and Tuple Spreads
This snippet demonstrates recursive generic conditional type deduction to type a variadic compose/pipe function. It inspects function arguments element-by-element using conditional `infer` types on tuple arrays, ensuring strict output-to-input type chaining across all transformations.
snippet.ts
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
type Func = (arg: any) => any;type Pipeline<F extends Func[]> = F extends [(arg: infer A) => infer B,...infer Rest]? Rest extends Func[]? (arg: A) => PipelineResult<B, Rest>: never: unknown;type PipelineResult<Input, F extends Func[]> = F extends [(arg: Input) => infer Next,...infer Rest]? Rest extends Func[]? PipelineResult<Next, Rest>: Next: Input;function pipe<F extends Func[]>(...fns: F): Pipeline<F> {return ((initial: any) =>fns.reduce((acc, fn) => fn(acc), initial)) as Pipeline<F>;}const processNumber = pipe((x: number) => x * 2,(x: number) => x.toString(),(x: string) => x.padStart(5, '0'));
Breakdown
1
type Pipeline<F extends Func[]> = F extends [ (arg: infer A) => infer B, ...infer Rest ]
Extracts the initial function argument type A and return type B using tuple head/tail destructuring.
2
type PipelineResult<Input, F extends Func[]> = ...
Recursively verifies that the return type of each function matches the argument type of the subsequent function.
3
fns.reduce((acc, fn) => fn(acc), initial)
Executes functions sequentially at runtime using a memory-efficient Array reduce loop.
4
const processNumber = pipe(...)
Produces a strictly typed composition pipeline with full type inference from number input to string output.