sveltejs / eslint-plugin-svelte

ESLint plugin for Svelte using AST
https://sveltejs.github.io/eslint-plugin-svelte/
MIT License
296 stars 35 forks source link

[Svelte 5] ESLint reports `no-undef` on generic type parameters #848

Closed karbica closed 2 weeks ago

karbica commented 2 weeks ago

Before You File a Bug Report Please Confirm You Have Done The Following...

What version of ESLint are you using?

^9.10.0

What version of eslint-plugin-svelte are you using?

^2.43.0

What did you do?

Configuration ```mjs import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; import eslintPluginSvelte from 'eslint-plugin-svelte'; import js from '@eslint/js'; import svelteParser from 'svelte-eslint-parser'; import tsEslint from 'typescript-eslint'; import tsParser from '@typescript-eslint/parser'; /** @type {import('eslint').Linter.Config} */ export default [ js.configs.recommended, ...tsEslint.configs.strict, ...eslintPluginSvelte.configs['flat/recommended'], eslintPluginPrettierRecommended, { rules: { semi: ['warn', 'always'], quotes: ['warn', 'single', { avoidEscape: true, allowTemplateLiterals: true }], 'no-nested-ternary': 'error', 'linebreak-style': ['error', 'unix'], 'no-cond-assign': ['error', 'always'], 'no-console': 'error', '@typescript-eslint/sort-type-constituents': 'error', 'sort-imports': [ 'error', { ignoreCase: true, ignoreDeclarationSort: false, ignoreMemberSort: false, memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'], allowSeparatedGroups: true, }, ], }, }, { files: ['**/*.svelte'], languageOptions: { parser: svelteParser, parserOptions: { parser: tsParser, }, }, rules: { 'svelte/no-target-blank': 'error', 'svelte/no-at-debug-tags': 'error', 'svelte/no-reactive-functions': 'error', 'svelte/no-reactive-literals': 'error', }, }, { ignores: ['.output/', '.wxt/', 'build/', 'dist/', '*.d.ts'], }, ]; ```
<script lang="ts" generics="T extends AnyFunction, R extends ReturnType<T>">
  type Props = { fn: T };

  const NOOP = () => {};
  const { fn }: Props = $props();

  export const state = fn ? (fn() as R) : NOOP();
</script>

What did you expect to happen?

I expected ESLint to ignore that line containing type parameters inside the generics attribute of script.

What actually happened?

ESLint caught that line and logged with:

/Users/karbi/repos/.../src/lib/components/Attach.svelte
   9:22  error  'T' is not defined  no-undef
  14:38  error  'R' is not defined  no-undef

Link to GitHub Repo with Minimal Reproducible Example

https://github.com/karbica/repro-type-generics-no-undef

Additional comments

I'm using WXT as the boilerplate. It has nothing to do with ESLint and it doesn't come with any ESLint dependencies or configurations.

Install the dependencies and then run the lint script with whatever package manager you are using. You'll see that ESLint detects the type parameters in the Svelte component against the no-undef rule.

I'm not sure if this on the plugin to solve or the user has to hack around their own ESLint configuration file.

I'm referencing the upcoming docs here: https://github.com/sveltejs/svelte/blob/main/documentation/docs/05-misc/03-typescript.md.

AlbertMarashi commented 2 weeks ago

+1 here

image

eslint: 'T' is not defined.

AlbertMarashi commented 2 weeks ago

Is this a regression? I could've sworn it was working before..

AlbertMarashi commented 2 weeks ago
    {
        files: ["**/*.svelte"],
        languageOptions: {
            parserOptions: {
                parser: ts.parser,
                svelteFeatures: {
                    experimentalGenerics: true,
                }
            },
        },
    },

Adding this to my eslint.config.js fixes the issue

karbica commented 2 weeks ago
    {
        files: ["**/*.svelte"],
        languageOptions: {
            parserOptions: {
                parser: ts.parser,
                svelteFeatures: {
                    experimentalGenerics: true,
                }
            },
        },
    },

Adding this to my eslint.config.js fixes the issue

I was missing the property svelteFeatures setting experimentalGenerics to true. After adding that, the lint logs no longer reported on T and R not being defined.

Instead, now the AnyFunction is reported as not defined:

8:39  error  'AnyFunction' is not defined  no-undef

Although I have it in a .d.ts file at the root of the project:

/// <reference types="svelte" />

// This type is to be used to extend generics, not anywhere else.
type AnyFunction = (...args: any[]) => any;

I feel like I'm adjusting window blinds here. Thanks for taking a look.

ota-meshi commented 2 weeks ago

You need to enable experimentalGenerics, as @AlbertMarashi already shared with you. The RFC has not been accepted yet, so this remains an experimental feature. https://github.com/sveltejs/rfcs/pull/38

Please refer to the typescript-eslint FAQ for issues with AnyFunction.

https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors