You could make the function generic in T, the element type of the output array (so if the array produces a [X, Y, Z][] then T is [X, Y, Z]) and then give the function a rest parameter whose of a mapped tuple/array type over T:

declare function zipComp<T extends any[]>(
    ...args: { [I in keyof T]: T[I][] }
): T[]

In the mapped type { [I in keyof T]: T[I][] }, for each numeric-like index I in the T array, the element type T[I] at that index is mapped to an array of those elements T[I][]. So if T is [X, Y, Z], then the mapped type is [X[], Y[], Z[]].

Note that because the mapped type in question is homomorphic (as described in What does "homomorphic mapped type" mean? ) the compiler is able to infer T from the value passed in for args. (If this weren't true, then inference might fail and we'd need to rewrite the call signature.)

Also note that rest argument types tend to be inferred as tuple types by the compiler instead of just unordered array types, which is what we want.

All of this means that, if args is of type [X[], Y[], Z[]] then the output will be of type [X, Y, Z][].


Or at least it should be; let's try it out:

const nb = zipComp([1, 2], [false, true]);
// const nb: [number, boolean][];

const sno = zipComp(["a", "b", "c"], [1, 2, 3], [{}, {}, {}]);
// const sno: [string, number, {}][];

const hmm = zipComp([""], [1], [true], [new Date()], [null], 
   [undefined], [Symbol()], [() => 2]);
// const hmm: [string, number, boolean, Date, null, 
//   undefined, symbol, () => 2][]

Looks good! The compiler happily produces the output type from the input type even with relatively long inputs.

Playground link to code

Answer from jcalz on Stack Overflow
🌐
Learn TypeScript
learntypescript.dev › 06 › l8-generic-rest
Using generic rest elements with tuple types | Learn TypeScript
The function also accepts a varying number of subsequent parameters that are collected into the things rest element. things is required to be a tuple of type T. Call the logThings function and pass "Bob" and three numbers as parameters. ... Function parameters can be thought of as a tuple. Typing function parameters as a tuple allow strongly-typed functions to be created that have varying parameters. Next up we will learn how to use the spread operator on a generic parameter.
🌐
GitHub
github.com › microsoft › TypeScript › issues › 1024
Typed ...rest parameters with generics · Issue #1024 · microsoft/TypeScript
November 1, 2014 - Is it possible to add type info to the rest parameters in a way that each individual parameter can have a different type? This works, but with this there can be any number parameters, and all have to have the same type: function myFunction<T>(...args:T[]) { } myFunction<number>(1, 3); It would be really useful if I could force the exact number of arguments and the types for each one, but all this within generics, so something like this (but this is obviously syntactically wrong):
Author   microsoft
🌐
TypeScript Tutorial
typescripttutorial.net › home › typescript tutorial › typescript rest parameters
TypeScript Rest Parameters
July 11, 2024 - Use rest parameters to allow a function to accept a variable number of arguments with the same or different types.
Top answer
1 of 2
4

You could make the function generic in T, the element type of the output array (so if the array produces a [X, Y, Z][] then T is [X, Y, Z]) and then give the function a rest parameter whose of a mapped tuple/array type over T:

declare function zipComp<T extends any[]>(
    ...args: { [I in keyof T]: T[I][] }
): T[]

In the mapped type { [I in keyof T]: T[I][] }, for each numeric-like index I in the T array, the element type T[I] at that index is mapped to an array of those elements T[I][]. So if T is [X, Y, Z], then the mapped type is [X[], Y[], Z[]].

Note that because the mapped type in question is homomorphic (as described in What does "homomorphic mapped type" mean? ) the compiler is able to infer T from the value passed in for args. (If this weren't true, then inference might fail and we'd need to rewrite the call signature.)

Also note that rest argument types tend to be inferred as tuple types by the compiler instead of just unordered array types, which is what we want.

All of this means that, if args is of type [X[], Y[], Z[]] then the output will be of type [X, Y, Z][].


Or at least it should be; let's try it out:

const nb = zipComp([1, 2], [false, true]);
// const nb: [number, boolean][];

const sno = zipComp(["a", "b", "c"], [1, 2, 3], [{}, {}, {}]);
// const sno: [string, number, {}][];

const hmm = zipComp([""], [1], [true], [new Date()], [null], 
   [undefined], [Symbol()], [() => 2]);
// const hmm: [string, number, boolean, Date, null, 
//   undefined, symbol, () => 2][]

Looks good! The compiler happily produces the output type from the input type even with relatively long inputs.

Playground link to code

2 of 2
0

This is quite peculiar and shouldn't actually error.

<T extends any[]> means that T should be of an array type.

A workaround would be to set the following in your tsconfig.json compilerOptions object.

"skipLibCheck": true
🌐
GeeksforGeeks
geeksforgeeks.org › typescript-rest-parameters-and-arguments
TypeScript Rest Parameters and Arguments - GeeksforGeeks
April 28, 2025 - Parameter type annotations are part of TypeScript's static typing system, and they help catch ty ... TypeScript Generic Parameter Defaults allow you to specify default values for generic type parameters.
🌐
Medium
medium.com › @coppieters.tim › typescript-generic-rest-parameters-and-tuple-types-in-practice-edc2bb0bdcb9
TypeScript Generic Rest Parameters and Tuple Types in Practice | by Tim Coppieters | JavaScript in Plain English
December 18, 2020 - What we actually want to tell the type system is that the arguments that are gathered in the authorize’s rest args are exactly the same as those of the auth fucntion. We can try this by using generic types, saying that the authorize function’s rest parameters is of type P and the auth functions’s rest parameter is of type T.
🌐
Byteback
byteback.dev › posts › ts-rest-parameter-types
Rest Parameter Types in TypeScript | Byte Back
TypeScript 3.0 introduced rest elements in tuple types. We define a generic type parameter to represent a type for the rest parameters that have been passed. A tuple type is inferred base on the arguments of a particular call.
🌐
TypeScript
typescriptlang.org › docs › handbook › release-notes › typescript-3-0.html
TypeScript: Documentation - TypeScript 3.0
TypeScript 3.0 adds support to multiple new capabilities to interact with function parameter lists as tuple types. TypeScript 3.0 adds support for: Expansion of rest parameters with tuple types into discrete parameters. Expansion of spread expressions with tuple types into discrete arguments. Generic rest parameters and corresponding inference of tuple types.
Find elsewhere
🌐
Tutorial Teacher
tutorialsteacher.com › typescript › rest-parameters
TypeScript Rest Parameters
When the number of parameters that ... "arguments" variable. However, with TypeScript, we can use the rest parameter denoted by ellipsis .......
🌐
TypeScript
typescriptlang.org › docs › handbook › 2 › functions.html
TypeScript: Documentation - More on Functions
A rest parameter appears after all other parameters, and uses the ... syntax: ... In TypeScript, the type annotation on these parameters is implicitly any[] instead of any, and any type annotation given must be of the form Array<T> or T[], or a tuple type (which we’ll learn about later).
🌐
LeanIX Engineering
engineering.leanix.net › blog › typescript-generics-advanced-function-types
TypeScript's Generics and Advanced Function Types | LeanIX Engineering
July 27, 2023 - This means that the function can take any number of arguments, as long as they are all numbers. ...ids: T: This is a rest parameter, which means it can take any number of arguments.
🌐
GitHub
github.com › microsoft › TypeScript › issues › 37673
Generic function with rest parameters does not infer or widen actual args to union type · Issue #37673 · microsoft/TypeScript
// A *self-contained* demonstration of the problem follows... function foo<T extends string | number>(...rest: T[]): T[] { return rest; } foo('a', 1); Expected behavior: Should compile without error and infer the return type of foo('a', 1) to be at least (string | number)[] or, better still, more accurately as ("a" | 1)[] ... src/main.ts:5:10 - error TS2345: Argument of type '1' is not assignable to parameter of type '"a"'. 5 foo('a', 1);
Author   microsoft
🌐
GeeksforGeeks
geeksforgeeks.org › rest-parameters-in-typescript
Rest Parameters in TypeScript - GeeksforGeeks
January 22, 2025 - Avoid Overuse: Use rest parameters ... ... TypeScript Rest Parameters allow functions to accept an indefinite number of arguments of the same type, collecting them into an array....
🌐
Better Stack
betterstack.com › community › guides › scaling-nodejs › rest-parameters-spread
Rest Parameters and Spread Syntax in TypeScript | Better Stack Community
November 27, 2025 - Rest parameters collect all remaining arguments into a typed array, enabling variadic functions with full type safety. The ... syntax before the last parameter tells TypeScript to gather all additional arguments into an array of the specified type.
🌐
GitHub
github.com › microsoft › TypeScript › issues › 3870
Rest type parameter in generics for use with intersection types · Issue #3870 · microsoft/TypeScript
July 15, 2015 - U would be the intersection of all rest parameters passed to assign() and the return value would expand to something like T & (U0 & ... UN). With the push for composable types and ES6 standardizing the above behavior (in Object.assign) a syntax for generics like this would be very useful. ... DuplicateAn existing issue was already createdAn existing issue was already createdSuggestionAn idea for TypeScriptAn idea for TypeScript
Author   microsoft