linter-bundle 2.20.0 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -2
- package/README.md +5 -0
- package/eslint/index.js +5 -0
- package/eslint/rules/no-unnecessary-typeof.js +196 -0
- package/eslint/rules/no-unnecessary-typeof.md +18 -0
- package/package.json +13 -12
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
-
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.
|
|
9
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.22.0...HEAD)
|
|
10
|
+
|
|
11
|
+
## [2.22.0] - 2022-09-19
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- [eslint] Updated `@typescript-eslint` from `5.37.0` to `5.38.0`
|
|
16
|
+
- [eslint] Updated `eslint-plugin-functional` from `4.3.1` to `4.3.2`
|
|
17
|
+
- [stylelint] Updated `postcss-scss` from `4.0.4` to `4.0.5`
|
|
18
|
+
- [stylelint] Updated `stylelint` from `14.11.0` to `14.12.0`
|
|
19
|
+
- [eslint] Improved [`no-unnecessary-typeof`](./eslint/rules/no-unnecessary-typeof.md) to cover more cases
|
|
20
|
+
|
|
21
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.21.0...v2.22.0)
|
|
22
|
+
|
|
23
|
+
## [2.21.0] - 2022-09-14
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- [eslint] New rule [`no-unnecessary-typeof`](./eslint/rules/no-unnecessary-typeof.md), which prevents `typeof` checks at runtime, if a `typeof` operant has only one type in TypeScript.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- [eslint] Updated `@typescript-eslint` from `5.36.1` to `5.37.0`
|
|
32
|
+
- [eslint] Updated `eslint` from `8.23.0` to `8.23.1`
|
|
33
|
+
- [eslint] Updated `eslint-import-resolver-typescript` from `3.5.0` to `3.5.1`
|
|
34
|
+
- [eslint] Updated `eslint-plugin-functional` from `4.2.2` to `4.3.1`
|
|
35
|
+
- [eslint] Updated `eslint-plugin-jest` from `27.0.1` to `27.0.4`
|
|
36
|
+
- [eslint] Updated `eslint-plugin-react` from `7.31.1` to `7.31.8`
|
|
37
|
+
|
|
38
|
+
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v2.20.0...v2.21.0)
|
|
10
39
|
|
|
11
40
|
## [2.20.0] - 2022-09-01
|
|
12
41
|
|
|
@@ -969,7 +998,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
969
998
|
|
|
970
999
|
### Added
|
|
971
1000
|
|
|
972
|
-
- [
|
|
1001
|
+
- [eslint/overrides-gatsby] New rule [`no-global-undefined-check`](./eslint/rules/no-global-undefined-check.md), which prevents `typeof window === 'undefined'` checks, which are often [the source of rehydration problems](https://www.joshwcomeau.com/react/the-perils-of-rehydration/) in Gatsby
|
|
973
1002
|
|
|
974
1003
|
[Show all code changes](https://github.com/jens-duttke/linter-bundle/compare/v1.1.0...v1.2.0)
|
|
975
1004
|
|
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ This setup is using the following additional plugins:
|
|
|
38
38
|
Beside that, the following additional rules are part of this bundle:
|
|
39
39
|
|
|
40
40
|
- [no-global-undefined-check](./eslint/rules/no-global-undefined-check.md)
|
|
41
|
+
- [no-unnecessary-typeof](./eslint/rules/no-unnecessary-typeof.md)
|
|
41
42
|
|
|
42
43
|
### stylelint
|
|
43
44
|
|
|
@@ -424,3 +425,7 @@ If you get such an error message:
|
|
|
424
425
|
the problem is most likely, that your `tsconfig.json` does not cover your JavaScript files and that you don't have a `jsconfig.json` file in your root directory. This is required by the `@typescript-eslint` to use TypeScript for linting of JavaScript files.
|
|
425
426
|
|
|
426
427
|
To solve this problem, either `"include"` your JavaScript files in your `tsconfig.json` (don't forget to set the compiler option `"checkJs"` to `true`) or create a `jsconfig.json` file in your root directory (this can be a copy of your `tsconfig.json` with an `"include"` of your JavaScript files).
|
|
428
|
+
|
|
429
|
+
### In VSCode, in every file, the first line shows the error `Definition for rule "no-unnecessary-typeof" was not found. eslint(no-unnecessary-typeof)`
|
|
430
|
+
|
|
431
|
+
Please ensure that you've added the configuration options as described above ("VSCode setup" > "ESLint").
|
package/eslint/index.js
CHANGED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file ESLint rule which ensures that a `typeof` operant has more than one type in TypeScript, to prevent unnecessary checks of types at runtime.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** @typedef {ts.Type & { intrinsicName?: string; types?: ts.Type[]; objectFlags?: ts.ObjectFlags; }} Type */
|
|
6
|
+
|
|
7
|
+
const ts = require('typescript');
|
|
8
|
+
|
|
9
|
+
const { ESLintUtils } = require('@typescript-eslint/utils');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @type {import('eslint').Rule.RuleModule}
|
|
13
|
+
*/
|
|
14
|
+
module.exports = {
|
|
15
|
+
meta: {
|
|
16
|
+
docs: {
|
|
17
|
+
description: 'If a `typeof` operant has only one type in TypeScript, it\'s unnecessary to check it\'s type at runtime.',
|
|
18
|
+
recommended: true
|
|
19
|
+
},
|
|
20
|
+
messages: {
|
|
21
|
+
textWithType: 'Unnecessary `typeof`, because the only possible type of `{{ name }}` is `{{ type }}`.',
|
|
22
|
+
textWithoutType: 'Unnecessary `typeof`, because there is only one possible type of `{{ name }}`.'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
create (context) {
|
|
26
|
+
return {
|
|
27
|
+
UnaryExpression (node) {
|
|
28
|
+
if (node.operator !== 'typeof' || node.argument.type !== 'Identifier') {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// @ts-expect-error -- Different type definitions for `Rule.RuleContext` in ESLint and @typescript-eslint
|
|
33
|
+
const parserServices = ESLintUtils.getParserServices(context);
|
|
34
|
+
const checker = parserServices.program.getTypeChecker();
|
|
35
|
+
|
|
36
|
+
// @ts-expect-error -- ESLint `Identifier` is not recognized as `Node` by @typescript-eslint
|
|
37
|
+
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node.argument);
|
|
38
|
+
|
|
39
|
+
/** @type {Type} */
|
|
40
|
+
const nodeType = checker.getTypeAtLocation(originalNode);
|
|
41
|
+
|
|
42
|
+
if (isSingleType(nodeType)) {
|
|
43
|
+
if (nodeType.intrinsicName) {
|
|
44
|
+
context.report({
|
|
45
|
+
node,
|
|
46
|
+
messageId: 'textWithType',
|
|
47
|
+
data: {
|
|
48
|
+
name: node.argument.name,
|
|
49
|
+
type: nodeType.intrinsicName
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
context.report({
|
|
55
|
+
node,
|
|
56
|
+
messageId: 'textWithoutType',
|
|
57
|
+
data: {
|
|
58
|
+
name: node.argument.name
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if the number of types equals one.
|
|
70
|
+
*
|
|
71
|
+
* @param {Type} type - TypeScript type node.
|
|
72
|
+
* @returns {boolean} Returns `true` if the `type` is only one specific type.
|
|
73
|
+
*/
|
|
74
|
+
function isSingleType (type) {
|
|
75
|
+
if (isAnyOrUnknown(type)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!type.types) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const firstType = type.types[0];
|
|
84
|
+
|
|
85
|
+
if (isAnyOrUnknown(firstType)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (let i = 1; i < type.types.length; i++) {
|
|
90
|
+
if (isDifferentType(type.types[i], firstType)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Check if the type is either `any` or `unknown`, which represents multiple types.
|
|
100
|
+
*
|
|
101
|
+
* @param {ts.Type} type - TypeScript type node.
|
|
102
|
+
* @returns {boolean} Returns `true` if the type is either `any` or `unknown`, or an object which is based on `unknown`.
|
|
103
|
+
*/
|
|
104
|
+
function isAnyOrUnknown (type) {
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- `symbol` on Object is `undefined` for `Omit<unknown, 'undefined'>`
|
|
106
|
+
return (type.flags === ts.TypeFlags.Any || type.flags === ts.TypeFlags.Unknown || (type.flags === ts.TypeFlags.Object && type.symbol === undefined));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Check if two types are identical.
|
|
111
|
+
*
|
|
112
|
+
* @param {Type} type1 - TypeScript type node.
|
|
113
|
+
* @param {Type} type2 - TypeScript type node.
|
|
114
|
+
* @returns {boolean} Returns `true` if both types are identical.
|
|
115
|
+
*/
|
|
116
|
+
function isDifferentType (type1, type2) {
|
|
117
|
+
if (isString(type1) && isString(type2)) { return false; }
|
|
118
|
+
if (isNumber(type1) && isNumber(type2)) { return false; }
|
|
119
|
+
if (isBigInt(type1) && isBigInt(type2)) { return false; }
|
|
120
|
+
if (isBoolean(type1) && isBoolean(type2)) { return false; }
|
|
121
|
+
if (isSymbol(type1) && isSymbol(type2)) { return false; }
|
|
122
|
+
|
|
123
|
+
if (type1.flags !== type2.flags) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (type1.flags === ts.TypeFlags.Object) {
|
|
128
|
+
if (isFunction(type1)) {
|
|
129
|
+
return !isFunction(type2);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return isFunction(type2);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Checks if the given `type` is a `string`.
|
|
140
|
+
*
|
|
141
|
+
* @param {Type} type - TypeScript type node.
|
|
142
|
+
* @returns {boolean} Returns `true` if the type is a `string`.
|
|
143
|
+
*/
|
|
144
|
+
function isString (type) {
|
|
145
|
+
return [ts.TypeFlags.String, ts.TypeFlags.StringLiteral, ts.TypeFlags.StringMapping].includes(type.flags);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Checks if the given `type` is a `number`.
|
|
150
|
+
*
|
|
151
|
+
* @param {Type} type - TypeScript type node.
|
|
152
|
+
* @returns {boolean} Returns `true` if the type is a `number`.
|
|
153
|
+
*/
|
|
154
|
+
function isNumber (type) {
|
|
155
|
+
return [ts.TypeFlags.Number, ts.TypeFlags.NumberLiteral].includes(type.flags);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Checks if the given `type` is a `bigint`.
|
|
160
|
+
*
|
|
161
|
+
* @param {Type} type - TypeScript type node.
|
|
162
|
+
* @returns {boolean} Returns `true` if the type is a `bigint`.
|
|
163
|
+
*/
|
|
164
|
+
function isBigInt (type) {
|
|
165
|
+
return [ts.TypeFlags.BigInt, ts.TypeFlags.BigIntLiteral].includes(type.flags);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Checks if the given `type` is a `boolean`.
|
|
170
|
+
*
|
|
171
|
+
* @param {Type} type - TypeScript type node.
|
|
172
|
+
* @returns {boolean} Returns `true` if the type is a `boolean`.
|
|
173
|
+
*/
|
|
174
|
+
function isBoolean (type) {
|
|
175
|
+
return [ts.TypeFlags.Boolean, ts.TypeFlags.BooleanLiteral].includes(type.flags);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Checks if the given `type` is a `symbol`.
|
|
180
|
+
*
|
|
181
|
+
* @param {Type} type - TypeScript type node.
|
|
182
|
+
* @returns {boolean} Returns `true` if the type is a `symbol`.
|
|
183
|
+
*/
|
|
184
|
+
function isSymbol (type) {
|
|
185
|
+
return [ts.TypeFlags.ESSymbol, ts.TypeFlags.UniqueESSymbol].includes(type.flags);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Checks if the given `type` is a `function`.
|
|
190
|
+
*
|
|
191
|
+
* @param {Type} type - TypeScript type node.
|
|
192
|
+
* @returns {boolean} Returns `true` if the type is a `function`.
|
|
193
|
+
*/
|
|
194
|
+
function isFunction (type) {
|
|
195
|
+
return (type.objectFlags === ts.ObjectFlags.Anonymous);
|
|
196
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Disallow unnecessary `typeof` checks (`no-unnecessary-typeof`)
|
|
2
|
+
|
|
3
|
+
## Rule Details
|
|
4
|
+
|
|
5
|
+
If a `typeof` operant has only one type in TypeScript, it's unnecessary to check it's type at runtime.
|
|
6
|
+
|
|
7
|
+
Examples of **incorrect** code for this rule:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
declare var myString: string;
|
|
11
|
+
|
|
12
|
+
if (typeof myString === 'string') {}
|
|
13
|
+
if (typeof myString === 'boolean') {}
|
|
14
|
+
|
|
15
|
+
declare var myBoolean: (boolean | string) & (boolean | number);
|
|
16
|
+
|
|
17
|
+
if (typeof myBoolean === 'boolean') {}
|
|
18
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "linter-bundle",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.22.0",
|
|
4
4
|
"description": "Ready-to use bundle of linting tools, containing configurations for ESLint, stylelint and markdownlint.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -40,26 +40,27 @@
|
|
|
40
40
|
"check-outdated": "npx --yes -- check-outdated --ignore-pre-releases"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
44
|
-
"@typescript-eslint/parser": "5.
|
|
45
|
-
"eslint": "
|
|
46
|
-
"eslint
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "5.38.0",
|
|
44
|
+
"@typescript-eslint/parser": "5.38.0",
|
|
45
|
+
"@typescript-eslint/utils": "5.38.0",
|
|
46
|
+
"eslint": "8.23.1",
|
|
47
|
+
"eslint-import-resolver-typescript": "3.5.1",
|
|
47
48
|
"eslint-import-resolver-webpack": "0.13.2",
|
|
48
49
|
"eslint-plugin-eslint-comments": "3.2.0",
|
|
49
|
-
"eslint-plugin-functional": "4.
|
|
50
|
+
"eslint-plugin-functional": "4.3.2",
|
|
50
51
|
"eslint-plugin-import": "2.26.0",
|
|
51
|
-
"eslint-plugin-jest": "27.0.
|
|
52
|
+
"eslint-plugin-jest": "27.0.4",
|
|
52
53
|
"eslint-plugin-jsdoc": "39.3.6",
|
|
53
54
|
"eslint-plugin-jsx-a11y": "6.6.1",
|
|
54
55
|
"eslint-plugin-node": "11.1.0",
|
|
55
56
|
"eslint-plugin-promise": "6.0.1",
|
|
56
|
-
"eslint-plugin-react": "7.31.
|
|
57
|
+
"eslint-plugin-react": "7.31.8",
|
|
57
58
|
"eslint-plugin-react-hooks": "4.6.0",
|
|
58
59
|
"eslint-plugin-unicorn": "43.0.2",
|
|
59
60
|
"markdownlint-cli": "0.32.2",
|
|
60
61
|
"micromatch": "4.0.5",
|
|
61
|
-
"postcss-scss": "4.0.
|
|
62
|
-
"stylelint": "14.
|
|
62
|
+
"postcss-scss": "4.0.5",
|
|
63
|
+
"stylelint": "14.12.0",
|
|
63
64
|
"stylelint-declaration-block-no-ignored-properties": "2.5.0",
|
|
64
65
|
"stylelint-order": "5.0.0",
|
|
65
66
|
"stylelint-scss": "4.3.0",
|
|
@@ -73,8 +74,8 @@
|
|
|
73
74
|
"devDependencies": {
|
|
74
75
|
"@types/eslint": "8.4.6",
|
|
75
76
|
"@types/micromatch": "4.0.2",
|
|
76
|
-
"@types/node": "18.7.
|
|
77
|
+
"@types/node": "18.7.18",
|
|
77
78
|
"stylelint-find-new-rules": "4.0.0",
|
|
78
|
-
"typescript": "4.8.
|
|
79
|
+
"typescript": "4.8.3"
|
|
79
80
|
}
|
|
80
81
|
}
|