Skip to content

Strict Reflect.apply Reflect.construct and Function.prototype.apply/call/bind #33889

Description

@BlackGlory

Search Terms

Reflect.apply
Reflect.construct
Function.prototype.apply
Function.prototype.call
Function.prototype.bind

Suggestion

These functions should not return any.

Related:
#212
#27028

Use Cases

function getString() {
  return 'string'
}

class ClassA {}

Reflect.apply(getString, null, []) // expected string but got any
Reflect.construct(ClassA, []) // expected ClassA but got any
Function.prototype.apply.call(getString, undefined) // expected string but got any
Function.prototype.call.call(getString, undefined) // expected string but got any
Function.prototype.bind.call(getString, undefined)() // expected string but got any

Examples

Reflect:

// old
function apply(target: Function, thisArgument: any, argumentsList: ArrayLike<any>): any;

// new
function apply<T>(target: (...args: any) => T, thisArgument: any, argumentsList: ArrayLike<any>): T;

// old
function construct(target: Function, argumentsList: ArrayLike<any>, newTarget?: any): any;

// new
function construct<T>(target: new (...args: any) => T, argumentsList: ArrayLike<any>, newTarget?: any): T;

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
    👆 Add a new compiler option
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Activity

  1. jablko commented on Oct 9, 2019

    @jablko
    Contributor

    I'd expect Function.prototype.apply(null, getString); to error, like (Function.prototype as CallableFunction).apply(null, getString);:

    error TS2684: The 'this' context of type 'CallableFunction' is not assignable to method's 'this' of type '(this: any, ...args: any[]) => unknown'.
      Type 'CallableFunction' provides no match for the signature '(this: any, ...args: any[]): unknown'.
    

    --stringBindCallApply should apply the CallableFunction interface to the Function global as well as to function instances?

  2. BlackGlory commented on Oct 10, 2019

    @BlackGlory
    Author

    The original use case code has an error and has been fixed.

    Since Reflect.apply is easier to use than Function.prototype.apply and Reflect.construct provides feature that Function.prototype does not have, maybe we don't need to apply CallableFunction interface to Function, we just need to improve Reflect.apply and Reflect.construct.

  3. jablko commented on Oct 10, 2019

    @jablko
    Contributor

    Just checking whether the spread operator available to you?

    const args = [];
    new ClassA(...args); // ClassA
  4. BlackGlory commented on Oct 11, 2019

    @BlackGlory
    Author

    This is not an issue about how to dynamically create an object instance.

  5. jablko commented on Oct 11, 2019

    @jablko
    Contributor

    Would you consider adding more information about your use case?

  6. zanminkian commented on Sep 16, 2024

    @zanminkian

    This issue is equivalent to say: add type guard for Reflect.apply under --strictBindCallApply.

    Example:

    function foo(name: string) {
      console.log(name)
    }
    
    foo.apply(null, [42]); // typescript will report type error, great!
    Function.prototype.apply.call(foo, null, [42]); // no error 😢
    Reflect.apply(foo, null, [42]); // no error 😢
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