So there is a little clause you may have missed:

Type checking requires spread elements to match up with a rest parameter.

Without Rest Parameter

But you can use a type assertion to go dynamic... and it will convert back to ES5 / ES3 for you:

function foo(x:number, y:number, z:number) { 
 console.log(x,y,z);
}
var args:number[] = [0, 1, 2];

(<any>foo)(...args);

This results in the same apply function call that you'd expect:

function foo(x, y, z) {
    console.log(x, y, z);
}
var args = [0, 1, 2];
foo.apply(void 0, args);

With Rest Parameter

The alternative is that it all works just as you expect if the function accepts a rest parameter.

function foo(...x: number[]) { 
 console.log(JSON.stringify(x));
}
var args:number[] = [0, 1, 2];

foo(...args);
Answer from Fenton on Stack Overflow
Top answer
1 of 4
86

So there is a little clause you may have missed:

Type checking requires spread elements to match up with a rest parameter.

Without Rest Parameter

But you can use a type assertion to go dynamic... and it will convert back to ES5 / ES3 for you:

function foo(x:number, y:number, z:number) { 
 console.log(x,y,z);
}
var args:number[] = [0, 1, 2];

(<any>foo)(...args);

This results in the same apply function call that you'd expect:

function foo(x, y, z) {
    console.log(x, y, z);
}
var args = [0, 1, 2];
foo.apply(void 0, args);

With Rest Parameter

The alternative is that it all works just as you expect if the function accepts a rest parameter.

function foo(...x: number[]) { 
 console.log(JSON.stringify(x));
}
var args:number[] = [0, 1, 2];

foo(...args);
2 of 4
14

I think @Fenton explains it very well but I would like to add some more documentation and possible solutions.

Solutions:

Function overload. I prefer this solution in this case because it keeps some kind of type safety and avoids ignore and any. The original method and function call does not need to be rewritten at all.

function foo(...args: number[]): void
function foo(x: number, y: number, z: number) {
  console.log(x, y, z);
}
var args: number[] = [0, 1, 2];

foo(...args);

Use @ts-ignore to ignore specific line, TypeScript 2.3

function foo(x: number, y: number, z: number) {
  console.log(x, y, z);
}
var args: number[] = [0, 1, 2];
// @ts-ignore
foo(...args);

Use as any.

function foo(x: number, y: number, z: number) {
  console.log(x, y, z);
}
var args: number[] = [0, 1, 2];

(foo as any)(...args);

Link with documentation regarding the spread operator:

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

Discussions regarding this:

https://github.com/Microsoft/TypeScript/issues/5296 https://github.com/Microsoft/TypeScript/issues/11780 https://github.com/Microsoft/TypeScript/issues/14981 https://github.com/Microsoft/TypeScript/issues/15375

🌐
GitBook
basarat.gitbook.io › typescript › future-javascript › spread-operator
Spread Operator | TypeScript Deep Dive
The spread operator allows you to easily place an expanded version of an array into another array. This is demonstrated in the example below:
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Operators › Spread_syntax
Spread syntax (...) - JavaScript | MDN
You can make an element present or absent in an array literal, depending on a condition, using a conditional operator. ... const isSummer = false; const fruits = ["apple", "banana", ...(isSummer ? ["watermelon"] : [])]; // ['apple', 'banana'] When the condition is false, we spread an empty ...
🌐
HowToDoInJava
howtodoinjava.com › home › typescript › typescript / javascript spread operator
TypeScript / JavaScript Spread Operator (with Examples)
July 3, 2023 - The spread operator is most widely used for method arguments in the form of rest parameters where more than 1 value is expected. A typical example can be a custom sum(...args) method which can accept any number of method arguments and add them ...
🌐
GeeksforGeeks
geeksforgeeks.org › typescript › how-to-use-spread-operator-in-typescript
How to use Spread Operator in TypeScript ? - GeeksforGeeks
July 23, 2025 - The spread operator in Typescript, denoted by three dots (`...`), is a powerful tool, that allows you to spread the elements of an array or objects into another array or objects.
🌐
Reddit
reddit.com › r/typescript › spread operator with array and object
r/typescript on Reddit: Spread operator with array and object
April 27, 2022 -

Edit: This seems to be an issue since 2016, and apparently, no fix (yet? since 2016) because it seems like just an edge case.

Hi all, I accidentally mistyped [ with { at line 4 in the code below and it passes compiler check. Should this happen and why does it behave like that?

        type Foo = number // just an example
        
        let t: Foo[] = [] // [1,2,3] 
        let c: Foo[] = {...t}
        console.log(c.map(e=>-e))

It took me a few minutes in a sea of code to realise what's wrong. Needless to say, it was quite frustrating, I'm sorry if this is a stupid question.

playground link

here is my tsconfig.json

        {
          "compilerOptions": {
            "target": "es5",
            "lib": [
              "dom",
              "dom.iterable",
🌐
Tim Mousk
timmousk.com › blog › typescript-spread-operator
How To Use The Spread Operator In TypeScript? – Tim Mouskhelichvili
March 27, 2023 - Use const assertion on the array (like I did in the example). As you can see, the spread operator is great when you need to copy an array into a new array, merge two arrays, or copy object properties into a new object. But remember that the spread operator only works well on primitive values because it does a shallow copy. If you want to clone objects, you can use a library like clone-deep to make it work. Here are some other TypeScript ...
Find elsewhere
🌐
Nicotsou
nicotsou.com › tltr-typescript-spread-operator
Master Spread Operator With TypeScript
The spread operator has a very friendly sibling; the rest operator. Both of them share the three ...
🌐
Gitbooks
hamednourhani.gitbooks.io › typescript-book › content › docs › spread-operator.html
Spread Operator · typescript-book
The spread operator allows you to easily place an expanded version of an array into another array. This is demonstrated in the example below:
🌐
Scaler
scaler.com › home › topics › typescript › spread syntax with ts tuples
Spread syntax with TS tuples - Typescript
May 4, 2023 - Let us understand this with the help of an example: Using the spread syntax (...) we have narrowed down the return type of calculate. The inferred type of employee is still (string | number)[]. So let us again see how to narrow down the return ...
🌐
GitHub
github.com › microsoft › TypeScript › issues › 32689
Spread operator for object types and interfaces · Issue #32689 · microsoft/TypeScript
August 2, 2019 - Provide an operator to be used ... also allowing for those properties to be selectively overridden. type SizeProps = { width: number, height: number } type MyProps = { ...SizeProps, width: number | string, foo: boolean, } ...
Published   Aug 02, 2019
🌐
+return
plusreturn.com › home › blog › tutorial › 6 awesome tricks with the spread and rest operators in typescript and javascript objects
6 Awesome Tricks with the Spread and Rest Operators in Typescript and Javascript Objects | +return
July 26, 2022 - The (...) spread and rest operators are powerful tools to manipulate your typescript and javascript objects. here are 5 ways for you to get the most out of this operator!
🌐
Learn TypeScript
learntypescript.dev › 06 › l9-generic-spread
Spreading generic tuple parameters | Learn TypeScript
We have spread the generic type parameters in the function parameter type annotations. ... A bit better, but still not as required. Let's help TypeScript by adding a return type annotation to the function:
🌐
Alexey Berezin
blog.beraliv.dev › 2021-07-05-spread-in-typescript
TypeScript spread operator for 2 object types
Let's have an example: ... If we have the same key in both objects, we use if from the second object. Otherwise, we get it from the first object. So let's iterate over all keys of two objects in TypeScript and check whether we have a key in ...
🌐
Upmostly
upmostly.com › home › typescript › simplifying your code with the spread operator
Mastering TypeScript's Spread Operator for Cleaner, More Flexible Code - Upmostly
February 22, 2023 - Here’s how you use the spread operator to clone an array: const users = ['adam', 'brian', 'carl']; const newUsers = [...users]; newUsers.pop(); console.log(newUsers); //adam, brian console.log(users); //adam, brian, carl ...
Top answer
1 of 1
9

TypeScript can fairly easily represent prepending a type onto a tuple type, called Cons<H, T> like this:

type Cons<H, T extends readonly any[]> =
    ((h: H, ...t: T) => void) extends ((...r: infer R) => void) ? R : never

type ConsTest = Cons<1, [2, 3, 4]>;
// type ConsTest = [1, 2, 3, 4]

You can use this definition along with conditional mapped tuple types to produce a Push<T, V> to append a type onto the end of a tuple:

type Push<T extends readonly any[], V> = Cons<any, T> extends infer A ?
    { [K in keyof A]: K extends keyof T ? T[K] : V } : never

type PushTest = Push<[1, 2, 3], 4>;
// type PushTest = [1, 2, 3, 4]

but this definition of Push is fragile. If the T tuple has optional elements, or if it comes from the parameter list of a function, you'll notice that the compiler "shifts" the optional markers and parameter names one element to the right:

type Hmm = (...args: Push<Parameters<(optStrParam?: string) => void>, number>) => void;
// type Hmm = (h: string | undefined, optStrParam?: number) => void

Parameter names are not really part of the type so while it's annoying it's not affecting the actual type. Appending an argument after an optional one is... strange, so I'm not sure what the right behavior there. Not sure if these are dealbreakers for you, but be warned.

Anyway your AugmentParam would look like:

type AugmentParam<F extends (...args: any[]) => any, ExtraParam> =
    (...args: Extract<Push<Parameters<F>, ExtraParam>, readonly any[]>)
        => ReturnType<F>

and it works (with the earlier caveats):

type F = (x: number) => boolean

type F2 = AugmentParam<F, string>
// type F2 = (h: number, x: string) => boolean

type F3 = AugmentParam<F2, boolean>
// type F3 = (h: number, h: string, x: boolean) => boolean

Okay, hope that helps. Good luck!

Link to code

🌐
Medium
pandey-sunil1987.medium.com › spread-operator-and-destructing-in-typescript-806bf8e3d5e6
Spread operator and destructing in typescript | by Sunil Pandey | Medium
January 2, 2023 - Object concatenation is possible in a similar way by spreading two objects inside the object braces while initializing.
🌐
Medium
medium.com › geekculture › a-caveat-on-javascripts-spread-operator-with-typescript-38ccc2fa000e
A caveat on JavaScript’s spread operator with TypeScript | by Taufan | Geek Culture | Medium
May 27, 2021 - A caveat on JavaScript’s spread operator with TypeScript Let’s kickoff this post with this code snippet. Both call to bodyMassIndex will not throw any warning on TypeScript, even though the …