Skip to content

Function apply does not accept argumentsΒ #57164

Open

Description

πŸ”Ž Search Terms

function arguments apply

πŸ•— Version & Regression Information

I assume this applies in every version.

⏯ Playground Link

https://tsplay.dev/N9231m

πŸ’» Code

function f() {}

(function () {
	f.apply(null, arguments);
}());

πŸ™ Actual behavior

arguments errors with Argument of type 'IArguments' is not assignable to parameter of type '[]'.(2345)

πŸ™‚ Expected behavior

No error.

Additional information about the issue

f.apply(null, arguments) is a universal idiom for decades, albeit one that's fallen out of favor in lieu of f(...arguments) - and when one needs to set the receiver, f.apply(O, arguments) is the only choice.

Somewhat related to #68307; basically, there should probably be an "arraylike" type that all of arrays and arguments and strings and nodelists can assign to.

Activity

  1. MartinJohns commented on Jan 25, 2024

    @MartinJohns
    Contributor

    Duplicate of #36470. The issue provides a workaround using a local declaration that supports IArguments for apply. Alternatively use a type assertion.

  2. ljharb commented on Jan 25, 2024

    @ljharb
    ContributorAuthor

    I can’t use a type assertion in jsdoc, so that’s not an option for me, nor do i wish to declare a global type (esp one that’s β€œunsafe” per that issue comment), so it doesn’t seem like i have any workaround.

  3. Andarist commented on Jan 25, 2024

    @Andarist
    Contributor

    You can always assert it at the call site:

    function f() {}
    
    (function () {
    	f.apply(null, arguments); // error
    
    	f.apply(null, /** @type {any} */(arguments)); // no error
    }());
  4. ljharb commented on Jan 25, 2024

    @ljharb
    ContributorAuthor

    Thanks, altho i wouldn’t want to cast it to any - and in my particular case i have a handful of places and I’d prefer not to litter my code with casts.

  5. MartinJohns commented on Jan 25, 2024

    @MartinJohns
    Contributor

    πŸ€·β€β™‚οΈ You only have those two options.

  6. ljharb commented on Jan 25, 2024

    @ljharb
    ContributorAuthor

    Then i guess it’s good i filed this issue :-)

  7. snarbies commented on Jan 29, 2024

    @snarbies

    I was going to suggest this could be fixed by automagically typing arguments as IArguments & Parameters<typeof CALLEE> but for some reason intersected tuples can not be spread.

    function abc(a: 'a', b: 'b', c:'c'){
        var x = arguments as Parameters<typeof abc> & IArguments;
    
        // WORKS: Accepts (tuple & IArguments) because it is 
        // assignable to an array
        abc.apply(null,x); 
    
        // ERROR: Can spread tuple but not (tuple & IArguments)
        abc(...x); 
        // A spread argument must either have a tuple 
        // type or be passed to a rest parameter. (2556)
    }
  8. RyanCavanaugh commented on Jan 29, 2024

    @RyanCavanaugh
    Member

    You can also turn off strictBindCallApply 🫠. The "right" fix would be for b/c/a to take ArrayLike<T> versions of their argument tuples, but we don't have any type like that right now and it would be a very expensive fix that would really only pay off in this exact scenario.

  9. ljharb commented on Jan 29, 2024

    @ljharb
    ContributorAuthor

    hmm, i wasn't aware of that setting, but i usually am loath to disable any of the strict settings.

    Would it be possible to augment the type of these methods to take | IArguments as a "cheap" fix, without needing to disable that option?

    Unfortunately this exact scenario is absurdly common in any code that's not transpiled and needs to support pre-ES6 envs :-/

  10. RyanCavanaugh commented on Jan 29, 2024

    @RyanCavanaugh
    Member

    Adding | IArguments is basically the same as turning off strictBindCallApply, since every array is an IArguments

  11. ljharb commented on Jan 29, 2024

    @ljharb
    ContributorAuthor

    ah ok, gotcha.

    It definitely would be amazing to have the proper ArrayLike<T> fix - for a lot of the builtin APIs - but this can sit open pending that, and I'll use the workaround of turning off strictBindCallApply.

  12. DanielRosenwasser commented on Jan 29, 2024

    @DanielRosenwasser
    Member

    I can’t use a type assertion in jsdoc

    Just as a heads up, you can. They are parenthesized expressions with an /** @type {...} */ comment preceding them.

    function f() {}
    
    (function () {
        f.apply(null, /** @type {any} */ (arguments));
    }());

    Playground Link

  13. ljharb commented on Jan 29, 2024

    @ljharb
    ContributorAuthor

    Daniel Rosenwasser (@DanielRosenwasser) ah right thanks, i'd figured that out since then (i had to disable the no-extra-parens eslint rule). i can't use a non-null assertion, still, tho :-/

    altho casting it to "any" doesn't feel like an option to me :-) what i'd want is to cast it to unknown[] or Parameters<f> or something

  14. added a commit that references this issue on Mar 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions