Skip to content

Commit 4447727

Browse files
authored
Add TypeScript to the linting process (MetaMask#13495)
This commit allows developers to write TypeScript files and lint them (either via a language server in their editor of choice or through the `yarn lint` command). The new TypeScript configuration as well as the updated ESLint configuration not only includes support for parsing TypeScript files, but also provides some compatibility between JavaScript and TypeScript. That is, it makes it possible for a TypeScript file that imports a JavaScript file or a JavaScript file that imports a TypeScript file to be linted. Note that this commit does not integrate TypeScript into the build system yet, so we cannot start converting files to TypeScript and pushing them to the repo until that final step is complete.
1 parent ea4181d commit 4447727

15 files changed

+2561
-101
lines changed

.depcheckrc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ ignores:
1919
- '@metamask/forwarder'
2020
- '@metamask/test-dapp'
2121
- '@metamask/design-tokens' # Only imported in index.css
22+
- '@tsconfig/node14' # required dynamically by TS, used in tsconfig.json
2223
- '@sentry/cli' # invoked as `sentry-cli`
2324
- 'chromedriver'
2425
- 'depcheck' # ooo meta

.eslintrc.js

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ module.exports = {
77
ignorePatterns: [
88
'app/vendor/**',
99
'builds/**/*',
10-
'dist/**/*',
1110
'development/chromereload.js',
11+
'dist/**/*',
12+
'node_modules/**/*',
1213
],
1314
overrides: [
1415
/**
@@ -41,6 +42,7 @@ module.exports = {
4142
path.resolve(__dirname, '.eslintrc.base.js'),
4243
path.resolve(__dirname, '.eslintrc.node.js'),
4344
path.resolve(__dirname, '.eslintrc.babel.js'),
45+
path.resolve(__dirname, '.eslintrc.typescript-compat.js'),
4446
],
4547
parserOptions: {
4648
sourceType: 'module',
@@ -50,6 +52,23 @@ module.exports = {
5052
// trust that all of the files specified above are indeed modules.
5153
'import/unambiguous': 'off',
5254
},
55+
settings: {
56+
'import/resolver': {
57+
// When determining the location of a `require()` call, use Node's
58+
// resolution algorithm, then fall back to TypeScript's. This allows
59+
// TypeScript files (which Node's algorithm doesn't recognize) to be
60+
// imported from JavaScript files, while also preventing issues when
61+
// using packages like `prop-types` (where we would otherwise get "No
62+
// default export found in imported module 'prop-types'" from
63+
// TypeScript because imports work differently there).
64+
node: {},
65+
typescript: {
66+
// Always try to resolve types under `<root>/@types` directory even
67+
// it doesn't contain any source code, like `@types/unist`
68+
alwaysTryTypes: true,
69+
},
70+
},
71+
},
5372
},
5473
/**
5574
* Modules (ES module syntax)
@@ -75,10 +94,82 @@ module.exports = {
7594
path.resolve(__dirname, '.eslintrc.base.js'),
7695
path.resolve(__dirname, '.eslintrc.node.js'),
7796
path.resolve(__dirname, '.eslintrc.babel.js'),
97+
path.resolve(__dirname, '.eslintrc.typescript-compat.js'),
7898
],
7999
parserOptions: {
80100
sourceType: 'module',
81101
},
102+
settings: {
103+
'import/resolver': {
104+
// When determining the location of an `import`, use Node's resolution
105+
// algorithm, then fall back to TypeScript's. This allows TypeScript
106+
// files (which Node's algorithm doesn't recognize) to be imported
107+
// from JavaScript files, while also preventing issues when using
108+
// packages like `prop-types` (where we would otherwise get "No
109+
// default export found in imported module 'prop-types'" from
110+
// TypeScript because imports work differently there).
111+
node: {},
112+
typescript: {
113+
// Always try to resolve types under `<root>/@types` directory even
114+
// it doesn't contain any source code, like `@types/unist`
115+
alwaysTryTypes: true,
116+
},
117+
},
118+
},
119+
},
120+
/**
121+
* TypeScript files
122+
*/
123+
{
124+
files: ['*.{ts,tsx}'],
125+
extends: [
126+
path.resolve(__dirname, '.eslintrc.base.js'),
127+
'@metamask/eslint-config-typescript',
128+
path.resolve(__dirname, '.eslintrc.typescript-compat.js'),
129+
],
130+
rules: {
131+
// Turn these off, as it's recommended by typescript-eslint.
132+
// See: <https://typescript-eslint.io/docs/linting/troubleshooting#eslint-plugin-import>
133+
'import/named': 'off',
134+
'import/namespace': 'off',
135+
'import/default': 'off',
136+
'import/no-named-as-default-member': 'off',
137+
138+
// Disabled due to incompatibility with Record<string, unknown>.
139+
// See: <https://github.com/Microsoft/TypeScript/issues/15300#issuecomment-702872440>
140+
'@typescript-eslint/consistent-type-definitions': 'off',
141+
142+
// Modified to include the 'ignoreRestSiblings' option.
143+
// TODO: Migrate this rule change back into `@metamask/eslint-config`
144+
'@typescript-eslint/no-unused-vars': [
145+
'error',
146+
{
147+
vars: 'all',
148+
args: 'all',
149+
argsIgnorePattern: '[_]+',
150+
ignoreRestSiblings: true,
151+
},
152+
],
153+
},
154+
settings: {
155+
'import/resolver': {
156+
// When determining the location of an `import`, prefer TypeScript's
157+
// resolution algorithm. Note that due to how we've configured
158+
// TypeScript in `tsconfig.json`, we are able to import JavaScript
159+
// files from TypeScript files.
160+
typescript: {
161+
// Always try to resolve types under `<root>/@types` directory even
162+
// it doesn't contain any source code, like `@types/unist`
163+
alwaysTryTypes: true,
164+
},
165+
},
166+
},
167+
},
168+
{
169+
files: ['*.d.ts'],
170+
parserOptions: {
171+
sourceType: 'script',
172+
},
82173
},
83174

84175
/**

.eslintrc.typescript-compat.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = {
2+
settings: {
3+
'import/extensions': ['.js', '.ts', '.tsx'],
4+
'import/parsers': {
5+
'@typescript-eslint/parser': ['.ts', '.tsx'],
6+
},
7+
},
8+
};

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,6 @@ notes.txt
4646
.nyc_output
4747

4848
.metamaskrc
49+
50+
# TypeScript
51+
tsout/

development/build/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ require('@babel/eslint-parser');
3939
require('@babel/eslint-plugin');
4040
require('@metamask/eslint-config');
4141
require('@metamask/eslint-config-nodejs');
42+
require('@typescript-eslint/parser');
4243
require('eslint');
4344
require('eslint-config-prettier');
4445
require('eslint-import-resolver-node');
46+
require('eslint-import-resolver-typescript');
4547
require('eslint-plugin-import');
4648
require('eslint-plugin-jsdoc');
4749
require('eslint-plugin-node');

jsconfig.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

lavamoat/build-system/policy-override.json

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
"@babel/eslint-plugin": true,
2020
"@metamask/eslint-config": true,
2121
"@metamask/eslint-config-nodejs": true,
22+
"@metamask/eslint-config-typescript": true,
23+
"@typescript-eslint/eslint-plugin": true,
2224
"eslint": true,
2325
"eslint-config-prettier": true,
2426
"eslint-plugin-import": true,
@@ -29,20 +31,58 @@
2931
"eslint-plugin-react-hooks": true
3032
}
3133
},
34+
"@typescript-eslint/eslint-plugin": {
35+
"packages": {
36+
"@typescript-eslint/experimental-utils": true,
37+
"@typescript-eslint/scope-manager": true,
38+
"debug": true,
39+
"eslint": true,
40+
"ignore": true,
41+
"regexpp": true,
42+
"semver": true,
43+
"tsutils": true,
44+
"typescript": true
45+
}
46+
},
47+
"@typescript-eslint/experimental-utils": {
48+
"builtin": {
49+
"path": true
50+
},
51+
"packages": {
52+
"@typescript-eslint/scope-manager": true,
53+
"@typescript-eslint/types": true,
54+
"eslint": true,
55+
"eslint-scope": true,
56+
"eslint-utils": true
57+
}
58+
},
59+
"@typescript-eslint/scope-manager": {
60+
"packages": {
61+
"@typescript-eslint/types": true,
62+
"@typescript-eslint/visitor-keys": true
63+
}
64+
},
65+
"@typescript-eslint/visitor-keys": {
66+
"packages": {
67+
"eslint-visitor-keys": true
68+
}
69+
},
3270
"eslint-module-utils": {
3371
"packages": {
72+
"@babel/eslint-parser": true,
73+
"@typescript-eslint/parser": true,
3474
"eslint-import-resolver-node": true,
35-
"@babel/eslint-parser": true
75+
"eslint-import-resolver-typescript": true
3676
}
3777
},
38-
"node-sass": {
39-
"native": true
40-
},
4178
"module-deps": {
4279
"packages": {
4380
"loose-envify": true
4481
}
4582
},
83+
"node-sass": {
84+
"native": true
85+
},
4686
"sass": {
4787
"env": "unfrozen",
4888
"builtin": {
@@ -51,6 +91,17 @@
5191
"globals": {
5292
"Buffer": true
5393
}
94+
},
95+
"tsutils": {
96+
"packages": {
97+
"typescript": true,
98+
"tslib": true
99+
}
100+
},
101+
"typescript": {
102+
"globals": {
103+
"globalThis": true
104+
}
54105
}
55106
}
56107
}

0 commit comments

Comments
 (0)