language-tools icon indicating copy to clipboard operation
language-tools copied to clipboard

TypeScript warning when using <svelte:element/> with sveltekit:prefetch attribute

Open pascalpp opened this issue 3 years ago • 5 comments
trafficstars

Describe the bug

I have a Button component that renders a dynamic tag using svelte:element. Sometimes it renders anchor tags, so I have applied sveltekit:prefetch to the element, but TypeScript complains that svelte:element doesn't support that attribute. The attribute still works as expected: when an anchor tag is rendered, the sveltekit:prefetch attribute is present and triggers the desired prefetching behavior on hover. When a different tag (e.g. button) is rendered, the sveltekit:prefetch attribute is also present, but seems to have no adverse effect.

Is there a 'valid' way to use this attribute on this element? Should the type definition of svelte:element be expanded to allow this usage?

Reproduction

I have a REPL explaining the issue, and the use case behind it, here: https://svelte.dev/repl/bfbeb5c43f21461c9cbd0fea3cd680cb?version=3.49.0

Logs

No response

System Info

System:
    OS: macOS 12.5
    CPU: (10) arm64 Apple M1 Pro
    Memory: 107.34 MB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.15.1 - /usr/local/bin/node
    Yarn: 1.22.19 - ~/.yarn/bin/yarn
    npm: 8.11.0 - /usr/local/bin/npm
  Browsers:
    Chrome: 104.0.5112.79
    Firefox: 101.0.1
    Safari: 15.6
    Safari Technology Preview: 16.0
  npmPackages:
    @sveltejs/adapter-auto: next => 1.0.0-next.63 
    @sveltejs/kit: next => 1.0.0-next.393 
    svelte: ^3.44.0 => 3.49.0 
    vite: ^3.0.0 => 3.0.3

Severity

annoyance

Additional Information

No response

pascalpp avatar Aug 04 '22 04:08 pascalpp

Hmmm. I would think this is correct behavior. In pure TypeScript you could do some type narrowing to make this work, but I'm not sure if there's a way to do that in markup.

In the meantime, I bet this would work:

{#if selected === 'a'}
 <a />
{:else}
<svelte:element />
{/if}

That does unfortunately force you to duplicate the wiring up of props, but I'd think it's the most "correct" way to do what you want to do.

I'd say this is purely a TS error which in this case we should fix, we can't know what svelte:element is so we should allow all attributes. Moving this to language-tools.

dummdidumm avatar Aug 04 '22 13:08 dummdidumm

There are kinda two issues here:

  • the typescript error
  • sveltekit:prefetch being adding where not needed (e.g. on a button)

so I wonder if the sveltekit:prefetch attribute could be modified to accept an expression, e.g.

<svelte:element this={tag} sveltekit:prefetch={tag === 'a'}>

similar to other 'true if present' attributes, like disabled which can be conditionalized with disabled={expression}.

pascalpp avatar Aug 04 '22 14:08 pascalpp

I'd say this is purely a TS error which in this case we should fix, we can't know what svelte:element is so we should allow all attributes. Moving this to language-tools.

Interesting -- I would've thought the allowable attributes on an unknown element would be the intersection of allowable attributes for every HTML element, not any, but I suppose being permissive is also a valid approach (and makes more sense now that I think about it!). Thanks. 🙂

By "all attributes" I meant what you mean, all valid attributes of all elements + the special ones (that's the problem here) 👍

dummdidumm avatar Aug 05 '22 07:08 dummdidumm