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
🌐
Convex
convex.dev › advanced › advanced concepts › spread operator
Spread Operator | TypeScript Guide by Convex
When you need to combine multiple arrays, the spread operator handles it without loops or helper methods. ... This approach works well with typescript array operations when you're joining data from different sources.
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Operators › Spread_syntax
Spread syntax (...) - JavaScript - MDN Web Docs - Mozilla
May 22, 2026 - The spread (...) syntax allows an iterable, such as an array or string, to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected. In an object literal, the spread syntax enumerates the properties of an object and adds the key-value ...
Discussions

Spread operator with array and object
The spread operator only copies enumerable own properties of objects, but typescript copies all properties of the object into the receiving type. So in your example, if t = [1, 2, 3], at runtime c = {'0': 1, '1': 2, '2': 3}, but typescript infers the type of c as containing map and all the other methods on an array object, which happens to be assignable to the array type. Typescript does not distinguish between enumerable and non-enumerable properties, so I'm not sure there's a way for the compiler to catch this. But unit tests would catch this! More on reddit.com
🌐 r/typescript
14
8
April 27, 2022
Typescript spread operator for type - Stack Overflow
I'm trying to define a type which gets a function type as a generic parameter and returns a function type which is the same as the input function type except it has one more argument at the end: ... More on stackoverflow.com
🌐 stackoverflow.com
Spread operator
Afraid not. Javascript get syntax does not create a property that is enumerable. It can be accessed directly but won't be accessed via an object spread or a for/in loop. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#using_getters_in_classes More on reddit.com
🌐 r/typescript
22
4
August 8, 2024
Adding arbitrary attributes to object using spread operator
It’s not really a bug. If they performed excess property checks with spreading, the resulting errors would be very awkward to work around. Generally, typescript doesn’t care about excess properties. This is why Object.keys emits strings and not keyof T. More on reddit.com
🌐 r/typescript
4
2
April 25, 2024
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
December 31, 2019 - The main objective of the spread operator is to spread the elements of an array or object.
🌐
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.
🌐
HowToDoInJava
howtodoinjava.com › home › typescript › typescript / javascript spread operator
TypeScript / JavaScript Spread Operator (with Examples)
July 3, 2023 - The spread operator is a new addition to the features available in the JavaScript ES6 version. The spread operator is used to expand or spread an iterable or an array in Typescript or Javascript. 1. When to use the Spread Operator?
🌐
Tim Mousk
timmousk.com › blog › typescript-spread-operator
How To Use The Spread Operator In TypeScript? – Tim Mouskhelichvili
March 27, 2023 - The spread operator allows to spread or expand iterable objects into individual elements.
Find elsewhere
🌐
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 - In the first operation, this means we’re modifying the same object. In the second operation, since we’re actually changing what newUsersObject.adam refers to, nothing happens with the original. You can also use the spread operator to merge two objects/arrays together.
🌐
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",
🌐
Scaler
scaler.com › home › topics › typescript › spread syntax with ts tuples
Spread syntax with TS tuples - Typescript
May 4, 2023 - It is the opposite of rest syntax, ... a string into its characters. The spread operator in typescript allows an iterable object like an array or a string to expand in places where 0+ arguments are expected....
🌐
xjavascript
xjavascript.com › blog › typescript-dot-dot-dot-operator
Understanding the TypeScript Spread Operator (`...`) — xjavascript.com
The spread operator in TypeScript allows an iterable (like an array or an object) to be expanded into individual elements. It essentially "spreads" out the contents of an iterable into a new context.
🌐
TypeScript
typescriptlang.org › docs › handbook › release-notes › typescript-2-1.html
TypeScript: Documentation - TypeScript 2.1
TypeScript injects a handful of helper functions such as __extends for inheritance, __assign for spread operator in object literals and JSX elements, and __awaiter for async functions.
🌐
xjavascript
xjavascript.com › blog › typescript-spread-operator
Mastering the TypeScript Spread Operator — xjavascript.com
When the spread operator is applied to an iterable, it expands the elements of that iterable into individual values. The spread operator can be used to expand an array into individual elements.
🌐
Technical Feeder
technicalfeeder.com › 2021 › 07 › spread-operator-three-dots-in-javascript-typescript
TypeScript/JavaScript Spread operator (three dots) | Technical Feeder
October 26, 2022 - The spread operator (three dots) is used to copy an array and expand an array to pass the values to another object or function parameters. It can also be used as rest parameters in a function to indicate that the function can take as many arguments ...
🌐
Nicotsou
nicotsou.com › tltr-typescript-spread-operator
The spread operator does more than you think
December 16, 2022 - It’s those ... that you see when you open most of the JavaScript files? Yes, those ones. The spread operator —spoiler alert— can spread the contents of an array or an object. It’s basically the opposite of destructuring.
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

🌐
YouTube
youtube.com › watch
💥 The Typescript Object Spread Operator - YouTube
This video is part of the Typescript: The Ultimate Bootcamp Course - https://angular-university.io/course/typescript-bootcampCheck out the PDF E-Books avail...
Published   June 22, 2022