# ESlint 配置 ```javascript= module.exports = { env: { browser: true, es2021: true, }, extends: [ 'plugin:react/recommended', 'plugin:react/jsx-runtime', 'standard', 'plugin:@typescript-eslint/recommended', ], parser: '@typescript-eslint/parser', parserOptions: { ecmaFeatures: { jsx: true, }, ecmaVersion: 'latest', sourceType: 'module', }, plugins: [ 'react', '@typescript-eslint', 'react-hooks', ], rules: { /** https://typescript-eslint.io/rules/comma-dangle */ 'comma-dangle': 'off', '@typescript-eslint/comma-dangle': ['error', { arrays: 'always-multiline', objects: 'always-multiline', imports: 'always-multiline', exports: 'always-multiline', functions: 'only-multiline', generics: 'ignore', }], /** https://typescript-eslint.io/rules/indent/ */ indent: 'off', '@typescript-eslint/indent': ['error', 2, { SwitchCase: 1, VariableDeclarator: 1, outerIIFEBody: 1, MemberExpression: 1, FunctionDeclaration: { parameters: 1, body: 1 }, FunctionExpression: { parameters: 1, body: 1 }, CallExpression: { arguments: 1 }, ArrayExpression: 1, ObjectExpression: 1, ImportDeclaration: 1, flatTernaryExpressions: false, ignoreComments: false, ignoredNodes: ['TemplateLiteral *', 'JSXElement', 'JSXElement > *', 'JSXAttribute', 'JSXIdentifier', 'JSXNamespacedName', 'JSXMemberExpression', 'JSXSpreadAttribute', 'JSXExpressionContainer', 'JSXOpeningElement', 'JSXClosingElement', 'JSXFragment', 'JSXOpeningFragment', 'JSXClosingFragment', 'JSXText', 'JSXEmptyExpression', 'JSXSpreadChild'], offsetTernaryExpressions: true, }], /** https://typescript-eslint.io/rules/type-annotation-spacing/ */ '@typescript-eslint/type-annotation-spacing': ['error'], /** https://typescript-eslint.io/rules/member-delimiter-style */ '@typescript-eslint/member-delimiter-style': ['error', { multiline: { delimiter: 'comma', requireLast: true, }, singleline: { delimiter: 'comma', requireLast: false, }, multilineDetection: 'brackets', }], /** https://typescript-eslint.io/rules/no-unused-vars */ 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'warn', /** https://typescript-eslint.io/rules/space-before-function-paren */ 'space-before-function-paren': 'off', '@typescript-eslint/space-before-function-paren': ['error', 'always'], /** https://typescript-eslint.io/rules/space-infix-ops */ 'space-infix-ops': 'off', '@typescript-eslint/space-infix-ops': ['error'], /** https://typescript-eslint.io/rules/semi */ semi: 'off', '@typescript-eslint/semi': ['error', 'never'], /** https://typescript-eslint.io/rules/no-use-before-define/ */ 'no-use-before-define': 'off', '@typescript-eslint/no-use-before-define': 'error', 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn', 'no-console': ['warn', { allow: ['warn', 'error'] }], /** 限定集中在一處管理 env,禁止在其他檔案直接取用 `process.env` */ 'no-process-env': ['error'], 'react/jsx-indent': ['warn', 2, { checkAttributes: true, indentLogicalExpressions: true, }], 'react/prop-types': 'off', 'react/jsx-indent-props': ['warn', 2], 'react/jsx-closing-bracket-location': ['warn', 'tag-aligned'], 'jsx-quotes': ['warn', 'prefer-double'], 'react/jsx-curly-spacing': ['warn', { when: 'never', children: true }], 'react/jsx-tag-spacing': ['warn', { closingSlash: 'never', beforeSelfClosing: 'always', afterOpening: 'never', beforeClosing: 'never', }], 'react/self-closing-comp': 'warn', 'react/jsx-fragments': 'warn', 'react/jsx-equals-spacing': [2, 'never'], }, } ``` ```json= { "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, } ``` ```bash= eslint --init yarn && yarn add eslint-config-standard eslint --fix . --ext .ts,.tsx ```