Description
Checklist
- I have tried restarting my IDE and the issue persists.
- I have read the FAQ and my problem is not listed.
Tell us about your environment
- ESLint version: 9.21.0
- eslint-plugin-vue version: 10.0.0
- Vue version: 3.5.13
- Node version: 22.14.0
- Operating System: macos
Please show your full configuration:
import { includeIgnoreFile } from "@eslint/compat";
import eslint from "@eslint/js";
import eslintPluginStylistic from "@stylistic/eslint-plugin";
import eslintPluginVitest from "@vitest/eslint-plugin";
import type { Linter } from "eslint";
import eslintPluginFileProgress from "eslint-plugin-file-progress";
import eslintPluginImportX from "eslint-plugin-import-x";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import eslintPluginVue from "eslint-plugin-vue";
import { resolve } from "node:path";
import tseslint from "typescript-eslint";
import eslintParserVue from "vue-eslint-parser";
const gitignorePath = resolve(import.meta.dirname, ".gitignore");
const eslintRules: Linter.RulesRecord = {
"arrow-body-style": ["error", "as-needed"],
curly: "error",
eqeqeq: ["error", "always", { null: "ignore" }],
"no-else-return": "error",
};
const tsRules: Linter.RulesRecord = {
// https://typescript-eslint.io/rules/no-unused-vars/#how-to-use
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
args: "all",
argsIgnorePattern: "^_",
caughtErrors: "all",
caughtErrorsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
varsIgnorePattern: "^_",
ignoreRestSiblings: true,
},
],
// Opinionated configuration
"@typescript-eslint/array-type": [
"error",
{ default: "array-simple", readonly: "generic" },
],
"@typescript-eslint/consistent-type-exports": "error",
"@typescript-eslint/consistent-type-imports": [
"error",
{
disallowTypeAnnotations: false,
fixStyle: "separate-type-imports",
prefer: "type-imports",
},
],
"@typescript-eslint/no-inferrable-types": [
"error",
{ ignoreParameters: true },
],
};
const config = tseslint.config(
//#region global
includeIgnoreFile(gitignorePath),
{
name: "manual ignores",
ignores: [
"eslint.config.ts",
"packages/storybook/.storybook",
"packages/storybook/scripts/storybook-publish.mjs",
],
},
{
name: "linter options",
linterOptions: {
reportUnusedDisableDirectives: "error",
},
},
//#endregion
//#region eslint (js)
eslint.configs.recommended,
{
name: "eslint overrides",
rules: eslintRules,
},
//#endregion
//#region typescript-eslint
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
{
name: "typescript-eslint overrides",
plugins: {
"@typescript-eslint": tseslint.plugin,
},
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
parserOptions: {
parser: tseslint.parser,
project: "./tsconfig.json",
warnOnUnsupportedTypeScriptVersion: false,
},
},
rules: {
...eslintRules,
// TODO cquadflieg 2024-10-11: These are even double enabled by typescript-eslint
"no-cond-assign": "off",
"no-constant-binary-expression": "off",
"no-control-regex": "off",
"no-empty": "off",
"no-fallthrough": "off",
"no-prototype-builtins": "off",
"no-unused-private-class-members": "off",
"no-useless-escape": "off",
// TODO cquadflieg 2024-10-30: Investigate later if these should be re-enabled (included in recommendedTypeChecked)
"@typescript-eslint/await-thenable": "off",
"@typescript-eslint/no-duplicate-type-constituents": "off",
"@typescript-eslint/no-empty-object-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/no-implied-eval": "off",
"@typescript-eslint/no-misused-promises": "off",
"@typescript-eslint/no-redundant-type-constituents": "off",
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/no-unnecessary-type-assertion": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-function-type": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/no-unused-expressions": "off",
"@typescript-eslint/no-wrapper-object-types": "off",
"@typescript-eslint/only-throw-error": "off",
"@typescript-eslint/prefer-promise-reject-errors": "off",
"@typescript-eslint/require-await": "off",
"@typescript-eslint/restrict-plus-operands": "off",
"@typescript-eslint/restrict-template-expressions": "off",
"@typescript-eslint/unbound-method": "off",
// TODO cquadflieg 2024-10-11: Investigate later if these should be re-enabled (included in stylisticTypeChecked)
"@typescript-eslint/class-literal-property-style": "off",
"@typescript-eslint/dot-notation": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/prefer-regexp-exec": "off",
"@typescript-eslint/prefer-string-starts-ends-with": "off",
...tsRules,
},
},
//#endregion
//#region import
eslintPluginImportX.flatConfigs.recommended,
eslintPluginImportX.flatConfigs.typescript,
{
name: "import overrides",
languageOptions: {
parser: tseslint.parser,
ecmaVersion: "latest",
sourceType: "module",
},
rules: {
// TODO cquadflieg 2024-10-18: Enable in separate MR
"import-x/default": "off",
"import-x/no-named-as-default": "off",
// Opinionated configuration
"import-x/consistent-type-specifier-style": ["error", "prefer-top-level"],
},
settings: {
"import-x/extensions": [".d.ts", ".js", ".mdx", ".mts", ".ts", ".vue"],
"import-x/parsers": {
"@typescript-eslint/parser": [".d.ts", ".mdx", ".mts", ".ts"],
"vue-eslint-parser": [".vue"],
},
},
},
//#endregion
//#region stylistic
{
name: "stylistic overrides",
plugins: {
"@stylistic": eslintPluginStylistic,
},
rules: {
"@stylistic/padding-line-between-statements": [
"error",
{ blankLine: "always", prev: "block-like", next: "*" },
],
"@stylistic/quotes": ["error", "double", { avoidEscape: true }],
},
},
//#endregion
//#region prettier
eslintPluginPrettierRecommended,
//#endregion
//#region eslint-plugin-vue
...eslintPluginVue.configs["flat/recommended"],
{
name: "vue overrides",
files: ["*.vue", "**/*.vue"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
parser: eslintParserVue,
parserOptions: {
parser: tseslint.parser,
project: "./tsconfig.json",
extraFileExtensions: [".vue"],
},
},
rules: {
...eslintRules,
// TODO cquadflieg 2024-10-11: Investigate later if these should be re-enabled (included in stylisticTypeChecked)
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/non-nullable-type-assertion-style": "off",
...tsRules,
// Not needed, because it's handled by prettier
"vue/html-indent": "off",
"vue/max-attributes-per-line": "off",
"vue/singleline-html-element-content-newline": "off",
// If we use `v-html`, we know what we are doing
"vue/no-v-html": "off",
// TODO cquadflieg 2024-10-25: Enable in separate MR
"vue/no-template-shadow": "off",
"vue/require-default-prop": "off",
"vue/require-prop-types": "off",
// Opinionated configuration
"vue/attribute-hyphenation": [
"error",
"always",
{
ignore: ["ariaDescribedby", "innerHTML"],
},
],
"vue/block-lang": [
"error",
{
script: {
lang: "ts",
},
},
],
"vue/block-order": [
"error",
{
order: ["script:not([setup])", "script[setup]", "template", "style"],
},
],
"vue/define-macros-order": [
"error",
{
order: [
"defineOptions",
"defineProps",
"defineEmits",
"defineModel",
"defineSlots",
],
defineExposeLast: true,
},
],
"vue/html-self-closing": [
"error",
{
html: {
component: "always",
normal: "never",
void: "always",
},
svg: "always",
math: "always",
},
],
},
},
//#endregion
{
name: "test overrides",
files: ["*.test.ts", "**/*.test.ts"],
plugins: {
vitest: eslintPluginVitest,
},
rules: {
"vue/one-component-per-file": "off",
...eslintPluginVitest.configs.recommended.rules,
"vitest/expect-expect": "off",
"vitest/no-alias-methods": "error",
"vitest/prefer-each": "error",
"vitest/prefer-to-have-length": "error",
"vitest/valid-expect": ["error", { maxArgs: 2 }],
},
settings: {
vitest: {
typecheck: true,
},
},
},
//#region file-progress
eslintPluginFileProgress.configs.recommended
//#endregion
);
export default config;
What did you do?
Updated from 9.33.0 to v10.0.0
<script lang="ts">
// a comment
// another comment
export type FilterEditorListOption<
TValue = string,
TValueKey extends string = "value",
TTextKey extends string = "text",
THtmlKey extends string = "html",
TDisabledKey extends string = "disabled",
> = Record<TValueKey, TValue> &
Partial<Record<TTextKey, string>> &
Partial<Record<THtmlKey, string>> &
Partial<Record<TDisabledKey, boolean>> &
Partial<Record<string, unknown>>;
export interface FilterEditorListProps<
TValue = string,
TValueKey extends string = "value",
TTextKey extends string = "text",
THtmlKey extends string = "html",
TDisabledKey extends string = "disabled",
> {
disabledField?: TDisabledKey;
htmlField?: THtmlKey;
textField?: TTextKey;
valueField?: TValueKey;
// more props
}
// omitted
</script>
<script
setup
lang="ts"
generic="
TValue = string,
TValueKey extends string = 'value',
TTextKey extends string = 'text',
THtmlKey extends string = 'html',
TDisabledKey extends string = 'disabled'
"
>
const props = withDefaults(
defineProps<
FilterEditorListProps<
TValue,
TValueKey,
TTextKey,
THtmlKey,
TDisabledKey
>
>(),
{
// @ts-expect-error: default is compatible with generic default
disabledField: "disabled",
// @ts-expect-error: default is compatible with generic default
htmlField: "html",
// @ts-expect-error: default is compatible with generic default
textField: "text",
// @ts-expect-error: default is compatible with generic default
valueField: "value",
// omitted
}
);
// omitted
</script>
<template>
<div>
<!-- omitted -->
</div>
</template>
What did you expect to happen?
Linting fine as in 9.33.0
What actually happened?
Error shows a conflict with @typescript-eslint/no-unused-vars
on line 4 related to the type
-keyword: export type FilterEditorListOption<
Need to find out if this has something todo with generics, or if it also happens on other places.
Oops! Something went wrong! :(
ESLint: 9.21.0
TypeError: Cannot read properties of undefined (reading 'type')
Occurred while linting /Users/shini/project/packages/app/src/components/filters/FilterEditorList.vue:4
Rule: "@typescript-eslint/no-unused-vars"
at /Users/shini/project/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.0_@typescript-eslint+parser@8.26.0_eslint@9.21.0__2a2173ae08b530503a9273d67d87e2f1/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:332:28
at Array.some (<anonymous>)
at isExported (/Users/shini/project/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.0_@typescript-eslint+parser@8.26.0_eslint@9.21.0__2a2173ae08b530503a9273d67d87e2f1/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:322:26)
at UnusedVarsVisitor.collectUnusedVariables (/Users/shini/project/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.0_@typescript-eslint+parser@8.26.0_eslint@9.21.0__2a2173ae08b530503a9273d67d87e2f1/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:120:21)
at UnusedVarsVisitor.collectUnusedVariables (/Users/shini/project/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.0_@typescript-eslint+parser@8.26.0_eslint@9.21.0__2a2173ae08b530503a9273d67d87e2f1/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:133:18)
at UnusedVarsVisitor.collectUnusedVariables (/Users/shini/project/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.0_@typescript-eslint+parser@8.26.0_eslint@9.21.0__2a2173ae08b530503a9273d67d87e2f1/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:50:36)
at collectVariables (/Users/shini/project/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.0_@typescript-eslint+parser@8.26.0_eslint@9.21.0__2a2173ae08b530503a9273d67d87e2f1/node_modules/@typescript-eslint/eslint-plugin/dist/util/collectUnusedVariables.js:603:30)
at collectUnusedVariables (/Users/shini/project/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.0_@typescript-eslint+parser@8.26.0_eslint@9.21.0__2a2173ae08b530503a9273d67d87e2f1/node_modules/@typescript-eslint/eslint-plugin/dist/rules/no-unused-vars.js:279:65)
at Program:exit (/Users/shini/project/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.0_@typescript-eslint+parser@8.26.0_eslint@9.21.0__2a2173ae08b530503a9273d67d87e2f1/node_modules/@typescript-eslint/eslint-plugin/dist/rules/no-unused-vars.js:439:36)
at ruleErrorHandler (/Users/shini/project/node_modules/.pnpm/eslint@9.21.0_jiti@2.4.2/node_modules/eslint/lib/linter/linter.js:1160:48)
ELIFECYCLE Command failed with exit code 2.
Repository to reproduce this issue
Trying to reproduce it here: https://github.com/Shinigami92/vue-eslint-2702
But right now I could not, so I need to investigate more what the cause is...
Got it! Reproducible is now it the third commit: Shinigami92/vue-eslint-2702@167481a