You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何ESLint检测index.html?TS规则触发报错排查

问题:为何ESLint会检测index.html文件?

我正在对NX Monorepo创建的AnalogJS项目进行ESLint代码检查,使用当前配置时出现问题(已知问题源于该配置,若从根ESLint配置的extends数组中删除该配置路径,一切运行正常)。


报错信息

ESLint: 9.12.0

TypeError: Cannot read properties of undefined (reading 'at')
Occurred while linting C:\Users\sergd\work\pohorony.by\pohorony.by\packages\analog-app\index.html:2
Rule: "@typescript-eslint/ban-ts-comment"
    at Program (C:\Users\sergd\work\pohorony.by\pohorony.by\node_modules\@typescript-eslint\eslint-plugin\dist\rules\ban-ts-comment.js:118:50)
    at ruleErrorHandler (C:\Users\sergd\work\pohorony.by\pohorony.by\node_modules\eslint\lib\linter\linter.js:1084:48)

index.html文件内容

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>MyApp</title>
    <base href="/" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="icon" type="image/x-icon" href="/favicon.ico" />
    <link rel="stylesheet" href="/src/styles.css" />
  </head>
  <body>
    <analog-app-root></analog-app-root>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

eslint.base.json配置

{
  "env": { "browser": true, "es2021": true, "node": true },
  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "./.eslintrc.angular.json", "prettier"],
  "ignorePatterns": ["*dist*"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "project": true,
    "sourceType": "module"
  },
  "plugins": ["@typescript-eslint"],
  "overrides": [
    {
      "files": ["*.ts"],
      "rules": {
        "@typescript-eslint/array-type": ["error", { "default": "array" }],
        "@typescript-eslint/explicit-function-return-type": "error",
        "@typescript-eslint/lines-between-class-members": "off",
        "@typescript-eslint/no-explicit-any": "off",
        "@typescript-eslint/no-non-null-assertion": "off",
        "@typescript-eslint/no-unnecessary-type-assertion": "error",
        "@typescript-eslint/no-unused-vars": "off",
        "block-spacing": ["warn", "always"],
        "curly": ["warn", "all"],
        "eol-last": "error",
        "import/prefer-default-export": "off",
        "import/no-unresolved": "error",
        "max-len": [
          "error",
          {
            "code": 120,
            "ignoreComments": true,
            "tabWidth": 2,
            "ignoreStrings": true
          }
        ],
        "max-lines-per-function": ["error", 80],
        "max-classes-per-file": "off",
        "no-console": "off",
        "no-debugger": "off",
        "no-multiple-empty-lines": ["error", { "max": 2, "maxBOF": 0, "maxEOF": 1 }],
        "no-param-reassign": ["error", { "props": false }],
        "no-plusplus": "off",
        "no-return-assign": 1,
        "no-restricted-syntax": ["off", "ForInStatement"],
        "no-underscore-dangle": "off",
        "no-template-curly-in-string": "warn",
        "no-unused-vars": "off",
        "object-curly-spacing": ["warn", "always"],
        "spaced-comment": ["error", "always", { "markers": ["!", "?", "//", "todo", "*"] }],

        "class-methods-use-this": "off",
        "@typescript-eslint/no-inferrable-types": "off",
        "@typescript-eslint/explicit-member-accessibility": [
          "error",
          {
            "accessibility": "explicit",
            "overrides": {
              "accessors": "explicit",
              "constructors": "off",
              "methods": "explicit",
              "properties": "explicit",
              "parameterProperties": "explicit"
            }
          }
        ]
      }
    },
    {
      "files": ["*.spec.ts", "*.test.ts"],
      "rules": {
        "max-lines-per-function": "off"
      }
    }
  ]
}

.eslintrc.angular.json配置

{
  "overrides": [
    {
      "files": ["*.ts"],
      "extends": ["plugin:@angular-eslint/template/process-inline-templates"],
      "rules": {
        "@angular-eslint/contextual-lifecycle": "error",
        "@angular-eslint/no-async-lifecycle-method": "error",
        "@angular-eslint/sort-lifecycle-methods": "error",
        "@angular-eslint/no-attribute-decorator": "warn",
        "@angular-eslint/component-max-inline-declarations": [
          "error",
          {
            "template": 10,
            "styles": 0,
            "animations": 40
          }
        ],
        "@angular-eslint/consistent-component-styles": "error",
        "@angular-eslint/contextual-decorator": "error",
        "@angular-eslint/component-class-suffix": "error",
        "@angular-eslint/directive-class-suffix": "error",
        "@angular-eslint/no-conflicting-lifecycle": "error",
        "@angular-eslint/no-duplicates-in-metadata-arrays": "error",
        "@angular-eslint/no-empty-lifecycle-method": "error",
        "@angular-eslint/no-input-rename": "error",
        "@angular-eslint/no-inputs-metadata-property": "error",
        "@angular-eslint/no-lifecycle-call": "error",
        "@angular-eslint/no-output-native": "error",
        "@angular-eslint/no-output-on-prefix": "error",
        "@angular-eslint/no-output-rename": "error",
        "@angular-eslint/no-outputs-metadata-property": "error",
        "@angular-eslint/no-queries-metadata-property": "error",
        "@angular-eslint/prefer-on-push-component-change-detection": "error",
        "@angular-eslint/prefer-output-readonly": "error",
        "@angular-eslint/prefer-standalone": "error",
        "@angular-eslint/use-lifecycle-interface": "error",
        "@angular-eslint/use-pipe-transform-interface": "error"
      }
    },
    {
      "files": ["*.html"],
      "rules": {
        "@angular-eslint/template/alt-text": "error",
        "@angular-eslint/template/no-call-expression": "error",
        "@angular-eslint/template/banana-in-box": "warn",
        "@angular-eslint/template/button-has-type": "error",
        "@angular-eslint/template/elements-content": "error",
        "@angular-eslint/template/eqeqeq": "error",
        "@angular-eslint/template/interactive-supports-focus": "error",
        "@angular-eslint/template/label-has-associated-control": "error",
        "@angular-eslint/template/mouse-events-have-key-events": "error",
        "@angular-eslint/template/no-inline-styles": [
          "error",
          {
            "allowBindToStyle": true,
            "allowNgStyle": true
          }
        ],
        "@angular-eslint/template/no-interpolation-in-attributes": "error",
        "@angular-eslint/template/no-negated-async": "error",
        "@angular-eslint/template/role-has-required-aria": "error"
      }
    }
  ]
}

解决方案

问题核心是全局配置的@typescript-eslint/parser及相关规则被错误应用到HTML文件上,导致TypeScript专属规则(如@typescript-eslint/ban-ts-comment)解析HTML时崩溃。

修复步骤:

  1. 隔离TypeScript配置
    将eslint.base.json中全局的parser、parserOptions、plugins和plugin:@typescript-eslint/recommended移动到*.ts的overrides块中,确保仅作用于TypeScript文件:

    {
      "env": { "browser": true, "es2021": true, "node": true },
      "extends": ["eslint:recommended", "./.eslintrc.angular.json", "prettier"],
      "ignorePatterns": ["*dist*"],
      "overrides": [
        {
          "files": ["*.ts"],
          "parser": "@typescript-eslint/parser",
          "parserOptions": {
            "ecmaVersion": "latest",
            "project": true,
            "sourceType": "module"
          },
          "plugins": ["@typescript-eslint"],
          "extends": ["plugin:@typescript-eslint/recommended"],
          "rules": {
            // 保留原TS规则
          }
        },
        // 其他overrides配置不变
      ]
    }
    
  2. 配置HTML专属解析器
    在.eslintrc.angular.json的*.html overrides块中添加Angular模板解析器,确保HTML文件用正确的解析器处理:

    {
      "files": ["*.html"],
      "parser": "@angular-eslint/template-parser",
      "rules": {
        // 保留原HTML规则
      }
    }
    
  3. 验证修复
    修改后重新运行ESLint检查,确认HTML文件不再触发TypeScript规则报错,检查流程恢复正常。

内容的提问来源于stack exchange,提问作者Raji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 04:59:51