Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(eslint-plugin): [no-invalid-this] allow "this" in class property …
…definitions (#2685)
  • Loading branch information
krisztianb committed Oct 18, 2020
1 parent 30a6951 commit dccb6ee
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 7 deletions.
35 changes: 28 additions & 7 deletions packages/eslint-plugin/src/rules/no-invalid-this.ts
Expand Up @@ -31,12 +31,33 @@ export default createRule<Options, MessageIds>({
defaultOptions: [{ capIsConstructor: true }],
create(context) {
const rules = baseRule.create(context);
const argList: boolean[] = [];

/**
* Since function definitions can be nested we use a stack storing if "this" is valid in the current context.
*
* Example:
*
* function a(this: number) { // valid "this"
* function b() {
* console.log(this); // invalid "this"
* }
* }
*
* When parsing the function declaration of "a" the stack will be: [true]
* When parsing the function declaration of "b" the stack will be: [true, false]
*/
const thisIsValidStack: boolean[] = [];

return {
...rules,
ClassProperty(): void {
thisIsValidStack.push(true);
},
'ClassProperty:exit'(): void {
thisIsValidStack.pop();
},
FunctionDeclaration(node: TSESTree.FunctionDeclaration): void {
argList.push(
thisIsValidStack.push(
node.params.some(
param =>
param.type === AST_NODE_TYPES.Identifier && param.name === 'this',
Expand All @@ -46,12 +67,12 @@ export default createRule<Options, MessageIds>({
rules.FunctionDeclaration(node);
},
'FunctionDeclaration:exit'(node: TSESTree.FunctionDeclaration): void {
argList.pop();
thisIsValidStack.pop();
// baseRule's work
rules['FunctionDeclaration:exit'](node);
},
FunctionExpression(node: TSESTree.FunctionExpression): void {
argList.push(
thisIsValidStack.push(
node.params.some(
param =>
param.type === AST_NODE_TYPES.Identifier && param.name === 'this',
Expand All @@ -61,14 +82,14 @@ export default createRule<Options, MessageIds>({
rules.FunctionExpression(node);
},
'FunctionExpression:exit'(node: TSESTree.FunctionExpression): void {
argList.pop();
thisIsValidStack.pop();
// baseRule's work
rules['FunctionExpression:exit'](node);
},
ThisExpression(node: TSESTree.ThisExpression): void {
const lastFnArg = argList[argList.length - 1];
const thisIsValidHere = thisIsValidStack[thisIsValidStack.length - 1];

if (lastFnArg) {
if (thisIsValidHere) {
return;
}

Expand Down
55 changes: 55 additions & 0 deletions packages/eslint-plugin/tests/rules/no-invalid-this.test.ts
Expand Up @@ -277,6 +277,28 @@ class A {
}
`,

// Class Properties.
`
class A {
b = 0;
c = this.b;
}
`,

`
class A {
b = new Array(this, 1, 2, 3);
}
`,

`
class A {
b = () => {
console.log(this);
};
}
`,

// Array methods.

`
Expand Down Expand Up @@ -613,6 +635,9 @@ obj.foo = function () {

errors,
},

// Class Methods.

{
code: `
class A {
Expand All @@ -628,6 +653,36 @@ class A {
errors,
},

// Class Properties.

{
code: `
class A {
b = new Array(1, 2, function () {
console.log(this);
z(x => console.log(x, this));
});
}
`,

errors,
},

{
code: `
class A {
b = () => {
function c() {
console.log(this);
z(x => console.log(x, this));
}
};
}
`,

errors,
},

// Class Static methods.

{
Expand Down

0 comments on commit dccb6ee

Please sign in to comment.