为什么 Eslint 在 .vue 文件中看不到全局 TypeScript 类型(no-undef)

OKT*_*TAV 6 typescript eslint vue.js

我的 Vue/TypeScript 项目中有一个全局类型。在.ts文件中,一切都很好,Eslint 看到了它,但在.vue文件中,Eslint 抛出类型未定义的错误。TypeScript 不会抛出任何错误并看到此类型。下面的配置和代码示例。

\n

包.json

\n
{\n  "dependencies": {\n    "@hse-design/core": "^1.1.0",\n    "@hse-design/vue": "^1.1.0",\n    "axios": "^0.21.1",\n    "cors": "^2.8.5",\n    "element-ui": "^2.12.0",\n    "faker": "^5.1.0",\n    "focus-visible": "^5.2.0",\n    "js-cookie": "^2.2.1",\n    "lodash": "^4.17.20",\n    "morgan": "^1.10.0",\n    "nprogress": "^0.2.0",\n    "path-to-regexp": "^6.2.0",\n    "register-service-worker": "^1.6.2",\n    "sanitize.css": "^12.0.1",\n    "vue": "^2.6.10",\n    "vue-class-component": "^7.2.6",\n    "vue-property-decorator": "^9.1.2",\n    "vue-router": "^3.1.2",\n    "vue-svgicon": "^3.2.6",\n    "vuex": "^3.1.1",\n    "vuex-class": "^0.3.2",\n    "vuex-module-decorators": "^1.0.1",\n    "yamljs": "^0.3.0"\n  },\n  "devDependencies": {\n    "@babel/plugin-proposal-optional-chaining": "^7.12.7",\n    "@babel/preset-typescript": "^7.13.0",\n    "@types/compression": "^1.7.0",\n    "@types/cors": "^2.8.8",\n    "@types/faker": "^5.1.4",\n    "@types/jest": "^26.0.21",\n    "@types/js-cookie": "^2.2.2",\n    "@types/lodash": "^4.14.165",\n    "@types/morgan": "^1.9.2",\n    "@types/node": "~14.14.35",\n    "@types/nprogress": "^0.2.0",\n    "@types/webpack-env": "^1.14.0",\n    "@types/yamljs": "^0.2.31",\n    "@typescript-eslint/eslint-plugin": "^4.22.1",\n    "@typescript-eslint/parser": "^4.22.1",\n    "@vue/cli-plugin-babel": "^4.5.12",\n    "@vue/cli-plugin-e2e-cypress": "^4.5.12",\n    "@vue/cli-plugin-eslint": "^4.5.12",\n    "@vue/cli-plugin-pwa": "^4.5.12",\n    "@vue/cli-plugin-typescript": "^4.5.12",\n    "@vue/cli-plugin-unit-jest": "^4.5.12",\n    "@vue/cli-service": "^4.5.12",\n    "@vue/eslint-config-standard": "^6.0.0",\n    "@vue/eslint-config-typescript": "^7.0.0",\n    "@vue/test-utils": "^1.0.0-beta.29",\n    "babel-core": "^7.0.0-bridge.0",\n    "babel-eslint": "^10.0.3",\n    "babel-loader": "^8.2.2",\n    "concurrently": "^6.0.0",\n    "core-js": "^3.12.0",\n    "eslint": "^7.25.0",\n    "eslint-config-airbnb-base": "^14.2.1",\n    "eslint-plugin-import": "^2.22.1",\n    "eslint-plugin-node": "^11.1.0",\n    "eslint-plugin-promise": "^4.3.1",\n    "eslint-plugin-standard": "^5.0.0",\n    "eslint-plugin-vue": "^7.9.0",\n    "fibers": "^5.0.0",\n    "jest": "^26.6.3",\n    "sass": "^1.22.10",\n    "sass-loader": "10.1.1",\n    "style-resources-loader": "^1.2.1",\n    "swagger-routes-express": "^3.2.1",\n    "ts-jest": "^26.5.4",\n    "ts-node-dev": "^1.0.0",\n    "typescript": "^4.2.3",\n    "vue-cli-plugin-element": "^1.0.1",\n    "vue-cli-plugin-style-resources-loader": "^0.1.3",\n    "vue-template-compiler": "^2.6.10",\n    "webpack": "^5.28.0"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

tsconfig.json

\n
{\n  "compilerOptions": {\n    "module": "ESNext",\n    "target": "ESNext",\n    "strict": true,\n    "jsx": "preserve",\n    "importHelpers": true,\n    "moduleResolution": "node",\n    "experimentalDecorators": true,\n    "emitDecoratorMetadata": true,\n    "esModuleInterop": true,\n    "allowSyntheticDefaultImports": true,\n    "resolveJsonModule": true,\n    "sourceMap": true,\n    "baseUrl": ".",\n    "types": [\n      "node",\n      "jest",\n      "webpack-env",\n    ],\n    "typeRoots": [\n      "./src/@types",\n      "./node_modules/@types"\n    ],\n    "paths": {\n      "@/*": [\n        "src/*"\n      ]\n    },\n    "lib": [\n      "esnext",\n      "dom",\n      "dom.iterable",\n      "scripthost"\n    ]\n  },\n  "include": [ "src/**/*", "tests/**/*" ],\n  "exclude": [ "node_modules" ]\n}\n
Run Code Online (Sandbox Code Playgroud)\n

.eslint.js

\n
module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    node: true,\n    es6: true\n  },\n  parser: \'vue-eslint-parser\',\n  parserOptions: {\n    parser: \'@typescript-eslint/parser\',\n    sourceType: \'module\',\n    ecmaVersion: 2020\n  },\n  plugins: [\n    \'vue\'\n  ],\n  rules: {\n    \'no-console\': process.env.NODE_ENV === \'production\' ? \'error\' : \'off\',\n    \'no-debugger\': process.env.NODE_ENV === \'production\' ? \'error\' : \'off\',\n    \'class-methods-use-this\': 0,\n    \'consistent-return\': 0,\n    \'import/no-cycle\': 0,\n    \'import/extensions\': 0,\n    \'import/no-extraneous-dependencies\': 0,\n    \'space-before-function-paren\': [2, \'never\'],\n    \'vue/array-bracket-spacing\': \'error\',\n    \'vue/arrow-spacing\': \'error\',\n    \'vue/block-spacing\': \'error\',\n    \'vue/brace-style\': \'error\',\n    \'vue/camelcase\': \'error\',\n    \'vue/comma-dangle\': \'error\',\n    \'vue/component-name-in-template-casing\': \'error\',\n    \'vue/eqeqeq\': \'error\',\n    \'vue/key-spacing\': \'error\',\n    \'vue/match-component-file-name\': \'error\',\n    \'vue/object-curly-spacing\': \'error\',\n    \'vue/max-attributes-per-line\': [\'error\', {\n      singleline: 3,\n      multiline: {\n        max: 1,\n        allowFirstLine: false\n      }\n    }]\n  },\n  extends: [\n    \'eslint:recommended\',\n    \'airbnb-base\',\n    \'plugin:vue/recommended\',\n    \'@vue/standard\',\n    \'@vue/typescript\'\n  ]\n}\n
Run Code Online (Sandbox Code Playgroud)\n

src/@types/typings.d.ts

\n
type MyType = {\n  value: any\n}\n
Run Code Online (Sandbox Code Playgroud)\n

src/App.vue

\n
<template>\n  <div id="app">\n    <router-view />\n  </div>\n</template>\n\n<script lang="ts">\nimport { Component, Vue } from \'vue-property-decorator\'\n\n@Component({\n  name: \'App\',\n})\nexport default class extends Vue {\n  myField: MyType = { value: 1 } // The error is here | \xd0\x9e\xd1\x88\xd0\xb8\xd0\xb1\xd0\xba\xd0\xb0 \xd0\xb7\xd0\xb4\xd0\xb5\xd1\x81\xd1\x8c\n</script>\n
Run Code Online (Sandbox Code Playgroud)\n

错误

\n
error: \'MyType\' is not defined (no-undef) at src/App.vue:15:12:\n  13 | })\n  14 | export default class extends Vue {\n> 15 |   myField: MyType = { value: 1 }\n     |            ^\n  16 | }\n  17 | </script>\n  18 | \n
Run Code Online (Sandbox Code Playgroud)\n

Joh*_*rop 12

typescript-eslint 的故障排除文档有一个关于此的条目:

no-undef lint 规则不使用 TypeScript 来确定存在的全局变量 - 相反,它依赖于 ESLint 的配置。

我们强烈建议您不要在 TypeScript 项目上使用 no-undef lint 规则。它提供的检查已经由 TypeScript 提供,无需配置 - TypeScript 只是在这方面做得更好。

他们建议no-undef通过向 ESLint 配置添加替代来禁用 TypeScript,如下所示:

overrides: [
  {
    files: ['*.ts', '*.vue'],
    rules: {
      'no-undef': 'off',
    },
  },
],
Run Code Online (Sandbox Code Playgroud)

请注意,这会对no-undef所有*.vue文件禁用,无论它们使用 TypeScript 还是 JavaScript。