8000 [FEAT] [no-this-alias] Add rule (#232) · kaicataldo/typescript-eslint@ebee203 · GitHub
[go: up one dir, main page]

10000
Skip to content

Commit ebee203

Browse files
j-f1JamesHenry
authored andcommitted
[FEAT] [no-this-alias] Add rule (typescript-eslint#232)
1 parent 3606353 commit ebee203

File tree

4 files changed

+252
-0
lines changed

4 files changed

+252
-0
lines changed

packages/eslint-plugin-typescript/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ This guarantees 100% compatibility between the plugin and the parser.
7878
| [`typescript/no-non-null-assertion`](./docs/rules/no-non-null-assertion.md) | Disallows non-null assertions using the `!` postfix operator (`no-non-null-assertion` from TSLint) | | |
7979
| [`typescript/no-object-literal-type-assertion`](./docs/rules/no-object-literal-type-assertion.md) | Forbids an object literal to appear in a type assertion expression (`no-object-literal-type-assertion` from TSLint) | | |
8080
| [`typescript/no-parameter-properties`](./docs/rules/no-parameter-properties.md) | Disallow the use of parameter properties in class constructors. (`no-parameter-properties` from TSLint) | | |
81+
| [`typescript/no-this-alias`](./docs/rules/no-this-alias.md) | Disallow aliasing `this` (`no-this-assignment` from TSLint) | | |
8182
| [`typescript/no-triple-slash-reference`](./docs/rules/no-triple-slash-reference.md) | Disallow `/// <reference path="" />` comments (`no-reference` from TSLint) | | |
8283
| [`typescript/no-type-alias`](./docs/rules/no-type-alias.md) | Disallow the use of type aliases (`interface-over-type-literal` from TSLint) | | |
8384
| [`typescript/no-unused-vars`](./docs/rules/no-unused-vars.md) | Prevent TypeScript-specific constructs from being erroneously flagged as unused | :heavy_check_mark: | |
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Disallow aliasing `this` (no-this-alias)
2+
3+
This rule prohibts assigning variables to `this`.
4+
5+
## Rule Details
6+
7+
Rationale from TSLint:
8+
9+
> Assigning a variable to `this` instead of properly using arrow lambdas may be a symptom of pre-ES6 practices
10+
> or not managing scope well.
11+
>
12+
> Instead of storing a reference to `this` and using it inside a `function () {`:
13+
>
14+
> ```js
15+
> const self = this;
16+
>
17+
> setTimeout(function () {
18+
> self.doWork();
19+
> });
20+
> ```
21+
>
22+
> Use `() =>` arrow lambdas, as they preserve `this` scope for you:
23+
>
24+
> ```js
25+
> setTimeout(() => {
26+
> this.doWork();
27+
> });
28+
> ```
29+
30+
31+
Examples of **incorrect** code for this rule:
32+
33+
(see the rationale above)
34+
35+
Examples of **correct** code for this rule:
36+
37+
(see the rationale above)
38+
39+
### Options
40+
41+
You can pass an object option:
42+
43+
```json5
44+
{
45+
"typescript/no-this-alias": ["error", {
46+
"allowDestructuring": true, // Allow `const { props, state } = this`; false by default
47+
"allowedNames": ["self"], // Allow `const self = this`; `[]` by default
48+
}],
49+
}
50+
```
51+
52+
## When Not To Use It
53+
54+
If you need to assign `this` to variables, you shouldn’t use this rule.
55+
56+
## Related to
57+
58+
- TSLint: [`no-this-assignment`](https://palantir.github.io/tslint/rules/no-this-assignment/)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* @fileoverview Disallow aliasing `this`
3+
* @author Jed Fox
4+
*/
5+
"use strict";
6+
7+
const util = require("../util");
8+
9+
//------------------------------------------------------------------------------
10+
// Rule Definition
11+
//------------------------------------------------------------------------------
12+
13+
module.exports = {
14+
meta: {
15+
docs: {
16+
description: "Disallow aliasing `this`",
17+
extraDescription: [util.tslintRule("no-this-assignment")],
18+
category: "Best Practices",
19+
recommended: false,
20+
url: util.metaDocsUrl("no-this-alias"),
21+
},
22+
fixable: null,
23+
schema: [
24+
{
25+
type: "object",
26+
additionalProperties: false,
27+
properties: {
28+
allowDestructuring: {
29+
type: "boolean",
30+
},
31+
allowedNames: {
32+
type: "array",
33+
items: {
34+
type: "string",
35+
},
36+
},
37+
},
38+
},
39+
],
40+
messages: {
41+
thisAssignment: "Unexpected aliasing of 'this' to local variable.",
42+
thisDestructure:
43+
"Unexpected aliasing of members of 'this' to local variables.",
44+
},
45+
},
46+
47+
create(context) {
48+
const { allowDestructuring = false, allowedNames = [] } =
49+
context.options[0] || {};
50+
51+
return {
52+
VariableDeclarator(node) {
53+
const { id, init } = node;
54+
55+
if (init.type !== "ThisExpression") return;
56+
if (allowDestructuring && node.id.type !== "Identifier") return;
57+
58+
if (!allowedNames.includes(id.name)) {
59+
context.report({
60+
node: id,
61+
messageId:
62+
id.type === "Identifier"
63+
? "thisAssignment"
64+
: "thisDestructure",
65+
});
66+
}
67+
},
68+
};
69+
},
70+
};
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/**
2+
* @fileoverview Disallow aliasing `this`
3+
* Some tests taken from TSLint: https://github.com/palantir/tslint/tree/c7fc99b5/test/rules/no-this-assignment
4+
* @author Jed Fox
5+
*/
6+
"use strict";
7+
8+
//------------------------------------------------------------------------------
9+
// Requirements
10+
//------------------------------------------------------------------------------
11+
12+
const rule = require("../../../lib/rules/no-this-alias"),
13+
RuleTester = require("eslint").RuleTester;
14+
15+
const idError = { messageId: "thisAssignment", type: "Identifier" };
16+
const destructureError = {
17+
messageId: "thisDestructure",
18+
type: "ObjectPattern",
19+
};
20+
const arrayDestructureError = {
21+
messageId: "thisDestructure",
22+
type: "ArrayPattern",
23+
};
24+
25+
//------------------------------------------------------------------------------
26+
// Tests
27+
//------------------------------------------------------------------------------
28+
29+
const ruleTester = new RuleTester({
30+
parser: "typescript-eslint-parser",
31+
});
32+
33+
ruleTester.run("no-this-alias", rule, {
34+
valid: [
35+
"const self = foo(this);",
36+
{
37+
code: `
38+
const { props, state } = this;
39+
const { length } = this;
40+
const { length, toString } = this;
41+
const [foo] = this;
42+
const [foo, bar] = this;
43+
`.trim(),
44+
options: [
45+
{
46+
allowDestructuring: true,
47+
},
48+
],
49+
},
50+
{
51+
code: "const self = this;",
52+
options: [
53+
{
54+
allowedNames: ["self"],
55+
},
56+
],
57+
},
58+
],
59+
60+
invalid: [
61+
{
62+
code: "const self = this;",
63+
options: [
64+
{
65+
allowDestructuring: true,
66+
},
67+
],
68+
errors: [idError],
69+
},
70+
{
71+
code: "const self = this;",
72+
errors: [idError],
73+
},
74+
{
75+
code: "const { props, state } = this;",
76+
errors: [destructureError],
77+
},
78+
{
79+
code: `
80+
var unscoped = this;
81+
82+
function testFunction() {
83+
let inFunction = this;
84+
}
85+
const testLambda = () => {
86+
const inLambda = this;
87+
};
88+
`.trim(),
89+
errors: [idError, idError, idError],
90+
},
91+
{
92+
code: `
93+
class TestClass {
94+
constructor() {
95+
const inConstructor = this;
96+
const asThis: this = this;
97+
98+
const asString = "this";
99+
const asArray = [this];
100+
const asArrayString = ["this"];
101+
}
102+
103+
public act(scope: this = this) {
104+
const inMemberFunction = this;
105+
const { act } = this;
106+
const { act, constructor } = this;
107+
const [foo] = this;
108+
const [foo, bar] = this;
109+
}
110+
}
111+
`.trim(),
112+
errors: [
113+
idError,
114+
idError,
115+
idError,
116+
destructureError,
117+
destructureError,
118+
arrayDestructureError,
119+
arrayDestructureError,
120+
],
121+
},
122+
],
123+
});

0 commit comments

Comments
 (0)
0