create-vue icon indicating copy to clipboard operation
create-vue copied to clipboard

eslint: @typescript-eslint error when add some rules

Open troy351 opened this issue 2 years ago • 17 comments

  • Create vue 2 project using following config QQ截图20220715152725

  • npm install

  • add rules inside .eslintrc.cjs

    rules: {
        "@typescript-eslint/prefer-optional-chain": "error"
    }
    
  • npm run lint

  • terminal error

    Error: Error while loading rule '@typescript-eslint/prefer-optional-chain': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.

FYI. Adding parserOptions: { project: ["tsconfig.json"] } to .eslintrc.cjs won't help. Maybe caused by eslint-plugin-vue or @typescript-eslint

troy351 avatar Jul 15 '22 10:07 troy351

related https://github.com/vuejs/vue-eslint-parser/issues/104#issuecomment-909082288

troy351 avatar Jul 18 '22 02:07 troy351

This is kinda complicated…

I've got a working configuration:

.eslintrc.cjs:

/* eslint-env node */
require("@rushstack/eslint-patch/modern-module-resolution");

module.exports = {
  root: true,
  extends: [
    "plugin:vue/vue3-essential",
    "eslint:recommended",
    "@vue/eslint-config-typescript/recommended",
    "@vue/eslint-config-prettier",
  ],
  rules: {
    "@typescript-eslint/prefer-optional-chain": "error",
  },
  parserOptions: {
    parser: "@typescript-eslint/parser",
    project: "./tsconfig.json",
  },
  overrides: [
    {
      files: ["vite.config.ts", ".eslintrc.cjs"],
      parserOptions: {
        parser: "@typescript-eslint/parser",
        project: "./tsconfig.config.json",
      },
    },
  ],
};

And add ".eslintrc.cjs" to the "include" array in tsconfig.config.json.


The trick here is that we can only have a single parser when project is used, thus the parser object set in @vue/eslint-config-typescript must be overriden https://github.com/vuejs/eslint-config-typescript/blob/75a6bde42c6aadc805d01f23bed23c0a9f2e4ada/index.js#L9-L17

And since we use solution-style tsconfigs in the project, some files in the project aren't covered by the root tsconfig.json, so we need to configure overrides for them. In this case, it's vite.config.ts and .eslintrc.cjs.

sodatea avatar Jul 19 '22 08:07 sodatea

It works, thanks! Should this be in doc or as a built-in?

troy351 avatar Jul 19 '22 09:07 troy351

It seems tsx failed to parse

<script lang="tsx">
import { defineComponent } from "vue";

export default defineComponent({
  render() {
    return <div></div>; // Parsing error: Type expected.
  },
});
</script>

troy351 avatar Jul 19 '22 09:07 troy351

Yeah, currently it seems not possible to use project with script lang="tsx" in .vue files:

parserOptions.ecmaFeatures.jsx

  • ...
  • For "unknown" extensions (.md, .vue):
    • If parserOptions.project is not provided:
      • The setting will be respected.
    • If parserOptions.project is provided (i.e. you are using rules with type information):
      • always parsed as if this is false

https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/README.md#parseroptionsecmafeaturesjsx

sodatea avatar Jul 20 '22 07:07 sodatea

So it's impossible to make everything works for now? I may disable those @typescript-eslint rules that requires project.

troy351 avatar Jul 20 '22 07:07 troy351

I'm afraid so 🙁

sodatea avatar Jul 20 '22 07:07 sodatea

It was the limitation of typescript-eslint or eslint-plugin-vue or eslint itself? If we can specify project for parserOptions.parser.ts, the problem maybe solved. But we can't as https://github.com/vuejs/vue-eslint-parser/issues/104#issuecomment-896638158 said.

"parserOptions": {
        "parser": {
            "ts": "@typescript-eslint/parser",
            "<template>": "espree"
        }
    }

troy351 avatar Jul 20 '22 08:07 troy351

I'm not sure. But from the description, that it works without project, I guess it's a limitation of TypeScript itself.

Because TypeScript never supports custom file extensions well. For example, to make TypeScript work well with .vue files, we have to use a custom command-line tool: https://github.com/johnsoncodehk/volar/tree/master/packages/vue-tsc

Maybe @typescript-eslint can make it work by using the vue-tsc version of the TypeScript language service instead of the official one. But it's only my guess; I'm not familiar with either tool's actual implementation.

sodatea avatar Jul 20 '22 08:07 sodatea

What a pity, disable rule @typescript-eslint/prefer-optional-chain could be the most acceptable result.

Should I leave this issue open?

troy351 avatar Jul 20 '22 08:07 troy351

Yeah, let's leave it open until I find a better place to document this limitation.

sodatea avatar Jul 20 '22 08:07 sodatea

Oh I forgot to mention that I used to use the old version @vue/[email protected] with [email protected] and it worked. Though new features like defineProps are not recognized.

/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
  root: true,
  env: {
    node: true,
  },
  extends: [
    'plugin:vue/essential',
    'eslint:recommended',
    '@vue/typescript/recommended', // this line was changed
    '@vue/eslint-config-prettier',
  ],
  rules: {
    '@typescript-eslint/prefer-optional-chain': 'error',
  },
}

troy351 avatar Jul 21 '22 09:07 troy351

Oh I forgot to mention that I used to use the old version @vue/[email protected] with [email protected] and it worked.

It might be caused by https://github.com/typescript-eslint/typescript-eslint/pull/4430 that triggers an undefined behavior in .vue files https://github.com/typescript-eslint/typescript-eslint/issues/4755#issuecomment-1080961338

sodatea avatar Jul 22 '22 08:07 sodatea

FYI, I just created a @vue/eslint-config-standard-with-typescript package. https://github.com/vuejs/eslint-config-standard/tree/main/packages/eslint-config-standard-with-typescript#readme

By default it only supports <script lang="ts"> in .vue, but you can opt-in to use other langs (not encouraged). You can take that as a reference.

I plan to do similar refactors in @vue/eslint-config-airbnb and @vue/eslint-config-typescript later, but that would require much more time, because there are too many rules.

sodatea avatar Jul 22 '22 08:07 sodatea

There are many other rules require project to be set, you can search getParserServices usage inside https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/src/rules to get the full list :)

troy351 avatar Jul 22 '22 08:07 troy351

This isn't an exact solution for vue.js, but for anyone coming here from search looking to solve this problem for ts-node or node based typescript, I was able to solve the "You have used a rule which requires parserServices to be generated" error as follows (local setup: node 18-lts):

Add tsconfig.json and .eslintrc.js to your .eslintignore. If on vscode, you may want to add .vscode/settings.json as well.

Then in your .eslintrc file, add a settings prop and here is the config I am using (you likely do not need all the plugins I am using):

{
  "parser": "@typescript-eslint/parser",
  "extends": [
    "plugin:@typescript-eslint/recommended",
    "plugin:import/recommended",
    "plugin:eslint-comments/recommended",
    "plugin:jsonc/recommended-with-jsonc"],
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": ["unicorn","@typescript-eslint"],
  "settings": {
    "import/resolver": {
      "node": { "extensions": [".js", ".mjs", ".ts", ".d.ts"] },
      "typescript": {
        "project": "./tsconfig.json"
      }
    }
  },
 "rules" : { ... }
}

This does not follow any instructions or guides I have found via Google, and yet it is the only solution I've found that actually works.

Your mileage may vary, but this worked for me. Also, remember to restart eslint after making this change (cmd+shift+p and then restart eslint)

wmelton avatar Dec 27 '22 21:12 wmelton

just another fyi, if you have this working but the error crops up anyway, make sure that you have a <script></script> part in your sfc, even if it's empty.

hmt avatar Jan 23 '23 08:01 hmt