vuejs / create-vue

🛠️ The recommended way to start a Vite-powered Vue project
Other
3.71k stars 423 forks source link

eslint: @typescript-eslint error when add some rules #123

Open troy351 opened 2 years ago

troy351 commented 2 years ago

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

troy351 commented 2 years ago

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

haoqunjiang commented 2 years ago

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.

troy351 commented 2 years ago

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

troy351 commented 2 years ago

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>
haoqunjiang commented 2 years ago

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

troy351 commented 2 years ago

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

haoqunjiang commented 2 years ago

I'm afraid so 🙁

troy351 commented 2 years ago

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"
        }
    }
haoqunjiang commented 2 years ago

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.

troy351 commented 2 years ago

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

Should I leave this issue open?

haoqunjiang commented 2 years ago

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

troy351 commented 2 years ago

Oh I forgot to mention that I used to use the old version @vue/eslint-config-typescript@10.0.0 with eslint-plugin-vue@8.7.1 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',
  },
}
haoqunjiang commented 2 years ago

Oh I forgot to mention that I used to use the old version @vue/eslint-config-typescript@10.0.0 with eslint-plugin-vue@8.7.1 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

haoqunjiang commented 2 years ago

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.

troy351 commented 2 years ago

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 :)

wmelton commented 1 year ago

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)

hmt commented 1 year ago

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.