sveltejs / svelte-eslint-parser

Svelte parser for ESLint
https://sveltejs.github.io/svelte-eslint-parser/
MIT License
90 stars 19 forks source link

Extract slot prop types from `$$Slots` #273

Open marekdedic opened 1 year ago

marekdedic commented 1 year ago

Description

In ota-meshi/eslint-plugin-svelte#347 I proposed a rule to require slots and their props to be typed. In this package, those types should be used if they're present.

An example of what currently doesn't work:

App.svelte:

<Component let:arrayProp={arrayValue}>
  {#each arrayValue.filter( (val) => val.length > 10 ) as val} <!-- HERE -->
    {val}
  {/each}
</Component>

Component.svelte:

<script lang="ts">
  interface $$Slots {
    default: { arrayProp: Array<string> };
  }
</script>

<slot arrayProp={["Hello", "World", "Hello World"]} />

Here, on the marked line, I get the eslint error @typescript-eslint/no-unsafe-call - I presume that's because the parser does not infer that arrayValue is of type Array<string> and leaves it as any...

marekdedic commented 1 year ago

Actually, in general, the parser should probably eventually support the whole RFC...

zaporter-work commented 4 months ago

I've also recently run into this.

However, I don't understand why this doesn't already work. It seems like the code is sound.

parser/converts/attrs.ts:buildLetDirectiveType generates:

  return `${String(componentName)}['$$slot_def'][${JSON.stringify(
    slotName,
  )}][${JSON.stringify(letName)}]`;

Which in your example should translate to Component['$$slot_def']["default"]["arrayProp"]

My LSP & my other svelte tools have no problems understanding the type of the let:xyz bind from a interface $$Slots {...}.

Does anyone know why this isn't working with eslint? I'd be happy to figure out how to fix this but I'm out of ideas right now.

EDIT: I understand that nothing is generated for $$Slots, but I don't understand why this code to type the let binding exists if there are no corresponding types that are generated

ptrxyz commented 1 week ago

I randomly stumbled into the same problem, coming from a different angle. My observation is, that this line won't work at all when the component is generic. I don't know how this could be fixed, the buildLetDirectiveType code would somehow have to infer the correct generics and put them to the output.