Skip to content

Commit 619fb51

Browse files
committed
feat(eslint): add eslint for react and typescript support
* Since eslint supports TS: https://eslint.org/blog/2019/01/future-typescript-eslint * If you are curious about the why part: microsoft/TypeScript#29288, see `Linting` section
1 parent ecdd4a7 commit 619fb51

9 files changed

+1059
-41
lines changed

.editorconfig

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# http://editorconfig.org
2+
3+
root = true
4+
5+
[*]
6+
indent_style = space
7+
indent_size = 2
8+
end_of_line = lf
9+
charset = utf-8
10+
trim_trailing_whitespace = true
11+
insert_final_newline = true
12+
13+
[*.md]
14+
trim_trailing_whitespace = false

.eslintrc.js

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* React rules: https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules
3+
*/
4+
module.exports = {
5+
ignorePatterns: ["*.config.js", "node_modules/", "dist"],
6+
parserOptions: {
7+
project: `./tsconfig.json`
8+
},
9+
plugins: [
10+
"@typescript-eslint",
11+
"eslint-comments",
12+
"promise",
13+
],
14+
extends: [
15+
"airbnb-typescript",
16+
"plugin:@typescript-eslint/recommended",
17+
"plugin:eslint-comments/recommended",
18+
"plugin:promise/recommended",
19+
"prettier",
20+
"prettier/react",
21+
"prettier/@typescript-eslint",
22+
],
23+
env: {
24+
browser: true,
25+
},
26+
rules: {
27+
// Too restrictive, writing ugly code to defend against a very unlikely scenario: https://eslint.org/docs/rules/no-prototype-builtins
28+
"no-prototype-builtins": "off",
29+
// https://basarat.gitbooks.io/typescript/docs/tips/defaultIsBad.html
30+
"import/prefer-default-export": "off",
31+
"import/no-default-export": "error",
32+
// Too restrictive: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md
33+
"react/destructuring-assignment": "off",
34+
// No jsx extension: https://github.com/facebook/create-react-app/issues/87#issuecomment-234627904
35+
"react/jsx-filename-extension": "off",
36+
// Since we're using TS, no need for propTypes
37+
"react/prop-types": "off",
38+
"react/state-in-constructor": "off",
39+
// Use function hoisting to improve code readability
40+
"no-use-before-define": [
41+
"error",
42+
{ functions: false, classes: true, variables: true },
43+
],
44+
// Makes no sense to allow type inferrence for expression parameters, but require typing the response
45+
"@typescript-eslint/explicit-function-return-type": [
46+
"error",
47+
{ allowExpressions: true, allowTypedFunctionExpressions: true },
48+
],
49+
"@typescript-eslint/no-use-before-define": [
50+
"error",
51+
{ functions: false, classes: true, variables: true, typedefs: true },
52+
]
53+
}
54+
};

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
.env.test.local
2020
.env.production.local
2121
.idea
22+
.eslintcache
2223

2324
npm-debug.log*
2425
yarn-debug.log*

.huskyrc.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module.exports = {
22
hooks: {
33
'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS',
4+
'pre-commit': 'yarn lint && lint-staged',
45
},
5-
};
6+
};

.lintstagedrc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
3+
"prettier --write"
4+
]
5+
}

package.json

+16-2
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
"react-dom": "^16.13.1"
1616
},
1717
"scripts": {
18-
"test": "yarn type-check",
18+
"test": "yarn type-check && yarn lint",
1919
"type-check": "tsc --noEmit",
2020
"type-check:watch": "yarn type-check -- --watch",
2121
"build:types": "tsc --emitDeclarationOnly",
2222
"build:js": "webpack --progress --mode=production",
23-
"build": "yarn build:types && yarn build:js"
23+
"build": "yarn build:types && yarn build:js",
24+
"lint": "eslint src/**/*{.ts,.tsx} --format=pretty",
25+
"format": "prettier --write src/**/*.{js,jsx,ts,tsx,json,css,scss,md}"
2426
},
2527
"eslintConfig": {
2628
"extends": "react-app"
@@ -51,8 +53,20 @@
5153
"@semantic-release/git": "^9.0.0",
5254
"@types/react": "^16.9.29",
5355
"@types/react-dom": "^16.9.5",
56+
"@typescript-eslint/eslint-plugin": "^2.26.0",
5457
"babel-loader": "^8.1.0",
58+
"eslint": "^6.8.0",
59+
"eslint-config-airbnb-typescript": "^7.2.0",
60+
"eslint-config-prettier": "^6.10.1",
61+
"eslint-formatter-pretty": "^3.0.1",
62+
"eslint-plugin-eslint-comments": "^3.1.2",
63+
"eslint-plugin-import": "^2.20.2",
64+
"eslint-plugin-jsx-a11y": "^6.2.3",
65+
"eslint-plugin-promise": "^4.2.1",
66+
"eslint-plugin-react": "^7.19.0",
5567
"husky": "^4.2.3",
68+
"lint-staged": "^10.1.1",
69+
"prettier": "^2.0.2",
5670
"semantic-release": "^17.0.4",
5771
"surge": "^0.21.3",
5872
"typescript": "^3.8.3",

src/App.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import React from 'react';
1+
import React, { ReactElement } from 'react';
22
import { Counter } from "./Counter";
33
import { Hello } from "./Hello";
44

5-
export function App() {
5+
export function App(): ReactElement {
66
return (
77
<div className="App">
8-
<Hello name={ 'react-webpack-typescript-babel' } />
8+
<Hello name="react-webpack-typescript-babel" />
99
<Counter />
1010
</div>
1111
);

src/Counter.tsx

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { Component } from 'react';
1+
import React, {Component, ReactElement} from 'react';
22

33
export interface CounterState {
44
value: number;
@@ -7,16 +7,17 @@ export interface CounterState {
77
export class Counter extends Component<{}, CounterState> {
88
readonly state: CounterState = { value: 0 };
99

10-
public render() {
10+
private handleIncrement = (): void => this.setState(prevState => ({ value: prevState.value + 1 }));
11+
12+
private handleDecrement = (): void => this.setState(prevState => ({ value: prevState.value - 1 }));
13+
14+
public render(): ReactElement {
1115
return (
1216
<>
1317
<div>{ this.state.value }</div>
14-
<button onClick={ this.handleIncrement }>+</button>
15-
<button onClick={ this.handleDecrement }>-</button>
18+
<button type="button" onClick={ this.handleIncrement }>+</button>
19+
<button type="button" onClick={ this.handleDecrement }>-</button>
1620
</>
1721
);
1822
}
19-
20-
private handleIncrement = () => this.setState({ value: this.state.value + 1 });
21-
private handleDecrement = () => this.setState({ value: this.state.value - 1 });
2223
}

0 commit comments

Comments
 (0)