Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stronger this typing? #49025

Closed
5 tasks done
m93a opened this issue May 9, 2022 · 1 comment
Closed
5 tasks done

Stronger this typing? #49025

m93a opened this issue May 9, 2022 · 1 comment
Labels
Duplicate An existing issue was already created

Comments

@m93a
Copy link

m93a commented May 9, 2022

Suggestion

The behavior of this in methods is one of the last features of JavaScript that is both unintuitive and not checked for by TypeScript. It is commonplace for both novice and experienced TypeScript programmers to accidentaly create a method (instead of an instance function) and then pass it as a callback. Currently, the only way to find out that one has made such a mistake is at runtime (yikes!).

I propose two small changes in the typechecking system which could be introduced as a strict rule (eg. strictThisArgument). Those changes would eliminate most of the mistakes that lead to unexpected values of this at runtime.

🔍 Search Terms

better this and bind, this.method is not a function, strict this, unbound method passed to map, filter, addEventListener compiles but fails at runtime, method as callback checking

✅ Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code — not if it's introduced as a strictness rule
  • 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, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

Introduce a strict rule that will:

  1. Automatically add the correct this signature to methods in a class
  2. Make this in function signatures unknown by default – ie. () => void would be equivalent to (this: unknown) => void

📃 Motivating Example

Consider the following example:

class ConstantShift {
    additiveConstant = 42;

    addToNum(n: number) {
        return n + this.additiveConstant;
    }
}

function addToNumStrong(this: ConstantShift, n: number) {
    return n + this.additiveConstant;
}

const nums = [0, 1, 5, 27];
const shift = new ConstantShift();

nums.map(shift.addToNum); // compiles, doesn't work
nums.map(addToNumStrong); // compiles, doesn't work

nums.map(shift.addToNum.bind(shift)); // compiles and works
nums.map(addToNumStrong.bind(shift)); // compiles and works

Link to playground.

This example might look artificial, but in essence it's what every React developer does when they want their component to listen to some event. Passing methods as callbacks is a thing that happens quite often in the JS world.

How would this suggestion change this behavior? The first step would change the signature of the addToNum method to:

addToNum(this: ConstantShift, n: number): number

and the second step would make map accept (this: unknown, x: number) => number as the callback.

This would be enough to make TypeScript correctly recognize whether the code will work correctly at runtime, as can be seen in this playground.

💻 Use Cases

Eliminates mistakes when working with methods and callbacks, and ultimately increases productivity.

@whzx5byb
Copy link

whzx5byb commented May 9, 2022

Duplicate of #7968.
See #6739 also for the explanation for removing --strictThisChecks flags.

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label May 9, 2022
@m93a m93a closed this as completed May 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants