vuejs/eslint-plugin-vue

vue/no-dupe-keys, vue/prop-name-casing, and likely others, do not work if using a referenced type

Closed this issue ยท 1 comments

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: eslint@9.34.0
  • eslint-plugin-vue version: eslint-plugin-vue@10.3.0
  • Vue version: vue@3.5.21
  • Node version:: v22.19.0
  • Operating System: MacOS 15.6.1

Please show your full configuration:

import { globalIgnores } from 'eslint/config'
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
import pluginVue from 'eslint-plugin-vue'
// import typescriptEslint from 'typescript-eslint';

// To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
// import { configureVueProject } from '@vue/eslint-config-typescript'
// configureVueProject({ scriptLangs: ['ts', 'tsx'] })
// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup

export default defineConfigWithVueTs(
  {
    name: 'app/files-to-lint',
    files: ['**/*.{ts,mts,tsx,vue}'],
  },

  globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),

  pluginVue.configs['flat/essential'],
  // typescriptEslint.configs.recommended,
  vueTsConfigs.recommended,

  {
    name: "other",
    rules: {
      "vue/prop-name-casing": "error"
      // "@typescript-eslint/no-floating-promises":"error",
      // "@typescript-eslint/return-await": ["error", "always"],

    }
  }
)

What did you do?

<template>
  <div >
    {{ foo }}
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import type { SomeType } from './types';
   // no error here!  
defineProps<SomeType>()

  // no error here!
  const foo = computed(() => {
    return "hello";
  });
</script>

where SomeType is

//types.ts
export type SomeType = {
  foo: string;
  "kebab-case-property": string;
}

What did you expect to happen?

If I use these types directly, then the plugin behaves fine

<template>
  <div >
    {{ foo }}
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue';



  defineProps<{
    foo: string;
    //Prop "kebab-case-property" is not in camelCase.eslintvue/prop-name-casing
    "kebab-case-property": string;
  }>()

  //Duplicate key 'foo'. May cause name collision in script or template tag.eslintvue/no-dupe-keys
  const foo = computed(() => {
    return "hello";
  });
</script>

What actually happened?

There is no error for either vue/no-dupe-keys or vue/prop-name-casing when referencing a type.

What's interesting, and how I discovered this, is that if you add the @typescript-eslint/no-floating-promises rule, then all of a sudden this starts working!

export default defineConfigWithVueTs(
  {
    name: 'app/files-to-lint',
    files: ['**/*.{ts,mts,tsx,vue}'],
  },

  globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),

  pluginVue.configs['flat/essential'],
  // typescriptEslint.configs.recommended,
  vueTsConfigs.recommended,

  {
    plugins: {
      "@typescript-eslint": typescriptEslint.plugin  //๐Ÿ‘ˆ
    },
    name: "other",
    rules: {
      "vue/prop-name-casing": "error",
      "@typescript-eslint/no-floating-promises":"error", //๐Ÿ‘ˆ


    }
  }
)

Repository to reproduce this issue

https://github.com/dwjohnston/vue-linting-issue

These rules are capable of detecting the referenced type, so this issue seems to be related to a configuration problem.
You need to explicitly tell the parser where your TypeScript project configuration lives.

As mentioned in a similar comment, try configuring project along with tsconfigRootDir.