Repository navigation
Recursive Variadic Tuples not working for functional pipelines #62479
Description
🔎 Search Terms
For a long time, reactive libraries including RxJS lacked a proper typing solution for pipelines.
A pipeline is an array of 0 or more operator functions through which data flows through.
const stream = pipeline<I, O>(
operator1,
operator2,
operatorn,
);Typing such a stream with I and O for the input and output types respectively, means each operator function needs to have the proper types inferred and/or enforced, too:
const stream = pipeline<I, O>(
operator1<I, T1>,
operator2<T1, T2>,
...
operatorn<TN, O>,
);So, the first operator is typed I => T1, and so on, with intermediate types, until the last one has TN => O
Multiple attempts have been made by different people and LLMS to find a way, including the use of recursive and variadic types, but with no luck so far.
My understanding is it should be feasible with variadic tuples, so I suspect there might be a TS bug.
Some older unsuccessful attempts made so far:
export type OperatorPipeline<I, O=I> =
[] |
[OperatorFunction<I, infer M>, ...OperatorPipeline<M, O>] |
[OperatorFunction<I, O>]
;
export type OperatorPipeline<I, O=I> =
[] |
[OperatorFunction<I, O>] |
[I, O] extends [infer FIRST, ...infer REST]
? FIRST extends OperatorFunction<I, infer M>
? REST extends OperatorFunction<M, O>
? [OperatorFunction<I, M>, ...OperatorPipeline<M, O>]
: never
: never
: never
;
export type OperatorPipeline<I, O, Ops extends OperatorFunction<any, any>[] = []> =
Ops extends []
? [] // 0 operators
: Ops extends [OperatorFunction<I, infer Next>] // 1 operator
? [OperatorFunction<I, Next>] & (Next extends O ? unknown : never)
: Ops extends [OperatorFunction<I, infer Next>, ...infer Rest] // 2+ operators
? Rest extends OperatorFunction<any, any>[]
? [OperatorFunction<I, Next>, ...OperatorPipeline<Next, O, Rest>]
: never
: never
;Related:
ReactiveX/rxjs#7481
🕗 Version & Regression Information
- This changed between versions ______ and _______
- This changed in commit or PR _______
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about _________
- I was unable to test this on prior versions because _______
⏯ Playground Link
No response
💻 Code
// Your code here🙁 Actual behavior
TS throws various errors when parsing any of the above, and variants. Not listing them all, as we don't actually know whether this is a bug or a missing feature yet.
🙂 Expected behavior
Variadic tuples should help typing a whole operator pipeline, every step of the way.
Additional information about the issue
No response
Activity
nmain commentedon Sep 23, 2025
This is either a duplicate of or very closely related to #30370, #25660, #12512, and/or #10247.
Perhaps there's some new ground covered in this ticket that those don't, but you should establish what that difference is first.
My search terms were
functional pipe variadic.jcalz commentedon Sep 23, 2025
Yeah, this looks like #30370 to me. My inclination here (given that I'm not 100% sure what your example means, so I'm guessing) would be to write
And this gives you behavior like
Playground link
It's not clear to me what more is needed here.
RyanCavanaugh commentedon Sep 23, 2025
Generally people want a call like
to get inferred types for each parameter, but this requires an unbounded number of inference passes, whereas we usually don't want algorithms that can do unbounded amounts of work since structural types can and do result in infinite recursion that's sometimes quite difficult to detect.
#30134 tracks completely changing how inference works but it's unlikely to happen.
jcalz commentedon Sep 23, 2025
In cases like this I usually give up on variadic stuff and just use method chaining instead, to get better inference:
Playground link
typescript-bot commentedon Sep 26, 2025
This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.