sveltejs / eslint-plugin-svelte

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

False positive when accessing custom component props #298

Open ptrxyz opened 1 year ago

ptrxyz commented 1 year ago

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

What version of ESLint are you using?

8.26.0

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

2.12.0

What did you do?

Configuration ``` module.exports = { root: true, parser: '@typescript-eslint/parser', extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking', 'plugin:svelte/recommended', ], plugins: ['@typescript-eslint'], ignorePatterns: ['*.cjs', 'svelte.config.js'], overrides: [ { files: ['*.svelte'], parser: 'svelte-eslint-parser', parserOptions: { parser: { ts: '@typescript-eslint/parser', typescript: '@typescript-eslint/parser', }, }, }, ], parserOptions: { sourceType: 'module', ecmaVersion: 2022, project: ['./tsconfig.json'], extraFileExtensions: ['.svelte'], }, env: { browser: true, es2017: true, node: true, }, } ```

Consider this component:

<script lang="ts">
    // comp.svelte
    export const value1 = 3
    export const api = {
        value2: 3,
        get value3() {
            return 1
        },
    }
</script>

I am importing it here:

<script lang="ts">
    import Comp from '$lib/comp.svelte'

    let x: Comp

    $: if (x) console.log(x.value1, x.api.value2, x.api.value3, x.doesNotExist)
</script>

<Comp bind:this={x} />

When I run pnpm lint, I get an error like this:

/tmp/eslint-test/src/routes/+page.svelte
  6:37  error  Unsafe member access .value2 on an `any` value  @typescript-eslint/no-unsafe-member-access
  6:51  error  Unsafe member access .value3 on an `any` value  @typescript-eslint/no-unsafe-member-access

✖ 2 problems (2 errors, 0 warnings)

However the api property is actually typed correctly and is not of type any. This is also correctly detected by Typescript, yet ESLint seems to not like it:

image

(Please also note that .doesNotExist does not cause any trouble. No idea why that would be ...)

What did you expect to happen?

I expected ESLint to not throw the error since .api is correctly typed.

What actually happened?

ESLint "thinks" .api is of type any and thus raises an error.

Link to GitHub Repo with Minimal Reproducible Example

https://github.com/ptrxyz/eslint-unsafe-member-example/tree/svelte-eslint-parser

Additional comments

ota-meshi commented 1 year ago

Thank you for posting the issue.

I already know the problem. I'm doing an experiment to solve the problem.

https://github.com/ota-meshi/typescript-eslint-parser-for-extra-files

At least I have it working in my project. https://github.com/ota-meshi/eslint-plugin-promise-playground/blob/4efb3d094056a45f87a86a4a2bc463d5ba9e9a9d/src/lib/eslint/ESLintEditor.svelte#L25-L29

If you are interested in it, please try it and give us feedback. (I haven't tried it, but it might work in combination with eslint-plugin-svelte3.)

ptrxyz commented 1 year ago

Oh yes, that seems to do it. Thanks a bunch!

Any chance you also have an idea why x.doesNotExist does not raise an error? Obviously the prop does not exist yet neither ESlint nor Typescript seem to care. Did I miss something? Is there a rule for that?

ota-meshi commented 1 year ago

I think it's because all default imported classes from *.svelte files are of type SvelteComponentDev.

https://github.com/sveltejs/svelte/blob/master/src/runtime/ambient.ts

ptrxyz commented 1 year ago

I think it's because all default imported classes from *.svelte files are of type SvelteComponentDev.

https://github.com/sveltejs/svelte/blob/master/src/runtime/ambient.ts

Ok, thanks. I know, this is not in the scope of this issue, but I am really lost on this. Do you know/could point me to something on how to properly type the component to make TS raise an error when I try to access an undefined member?

ota-meshi commented 1 year ago

You can try the typescript-eslint-parser-for-extra-files. https://github.com/ota-meshi/typescript-eslint-parser-for-extra-files

This is a project for passing proper types to @typescript-eslint for *.svelte etc.