Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<svelte:element> parameter has an 'any' type with an inline handler #2003

Open
AlbertMarashi opened this issue Dec 25, 2022 · 26 comments
Open

Comments

@AlbertMarashi
Copy link

AlbertMarashi commented Dec 25, 2022

Edit: I have hidden the old issue that was solved, but this thread contained two issues

Old issue

Describe the bug

Getting a typescript issue where <svelte:element> is erroring when I use href attribute on an element that may either be an anchor link or a div.

Object literal may only specify known properties, and '"href"' does not exist in type 'HTMLAttributes<any>'.

image

This causes no actual compilation errors, but it does appear as an error in the IDE which is annoying

Reproduction

https://github.com/AlbertMarashi/element-bug-1

Logs

No response

System Info

System:
    OS: macOS 12.6.2
    CPU: (8) arm64 Apple M1 Pro
    Memory: 88.88 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.17.0 - /usr/local/bin/node
    npm: 8.15.0 - /usr/local/bin/npm
  Browsers:
    Chrome: 108.0.5359.124
    Firefox: 105.0.1
    Firefox Developer Edition: 109.0
    Safari: 15.6.1
  npmPackages:
    svelte: ^3.55.0 => 3.55.0

Severity

annoyance

I'm getting these issues with the e being untyped with svelte:elements

<svelte:element
    this={ unit ? "a" : "div" }
    class="paginator"
    class:active={ unit !== null }
    class:next={ direction === "next" }
    href={unit ? `/courses/${course.slug}/${unit.unit_slug}` : undefined}
    on:click={ pressed }
    on:keyup={ e => e.key === "Enter" && pressed() }>
...

Parameter 'e' implicitly has an 'any' type

#2003 (comment)

@msf-caesar
Copy link

msf-caesar commented Dec 30, 2022

Remember that you can use the {#if } blocks for different cases, and mix some properties in this way. This will allow you to have more control when splitting your element and deciding how you want it to compile. Don't forget to keep this in mind.

@AlbertMarashi
Copy link
Author

#2003

The point of svelte:element is to remove the need for unnecessary {#if} blocks

@yastanotheruser
Copy link

This is an editor/language server issue. I replicated the same example using Vite and TypeScript and got no errors neither from the language server nor the build.

@AlbertMarashi
Copy link
Author

I'm getting this issue in tonnes of components and it's quite annoying since it creates all of these unfixable typescript errors everywhere.

@jasonlyu123
Copy link
Member

You can fix the error if you type the tag variable as a literal type like

let tag: 'a' | 'button' = 'a'

@AlbertMarashi
Copy link
Author

AlbertMarashi commented Apr 25, 2023

@dummdidumm could this get some attention please? I'm getting littered with tonnes of these errors across my project
Object literal may only specify known properties, and '"href"' does not exist in type 'HTMLAttributes<any>'.

I feel like it's a common usecase to use svelte:elements to conditionally render an a tag or some other kind of element which responds to on:click events.

I'm also getting these issues with the e being untyped with svelte:elements

<svelte:element
    this={ unit ? "a" : "div" }
    class="paginator"
    class:active={ unit !== null }
    class:next={ direction === "next" }
    href={unit ? `/courses/${course.slug}/${unit.unit_slug}` : undefined}
    on:click={ pressed }
    on:keyup={ e => e.key === "Enter" && pressed() }>
...

Parameter 'e' implicitly has an 'any' type

Some related issues:
#1913
#1977
sveltejs/svelte#8335

@jasonlyu123 jasonlyu123 transferred this issue from sveltejs/svelte May 8, 2023
@jasonlyu123
Copy link
Member

The Object literal may only specify known properties, and '"href"' does not exist in type 'HTMLAttributes<any>' error can be fixed if you use literal type for element tag. If it doesn't, You're likely still using svelte-check v2 or extension v106. Please update to the latest version.

As for the event handler, It seems like TypeScript can't infer it from the union signature. Not sure what we can do about it. But it works if you move it to the script tag with an implicit parameter type. TypeScript will error with the wrong parameter type but can't infer the exact type for an inline handler. Transferring because this can't be fixed in svelte/element but has something to do with the svelte2tsx internal helper.

@jasonlyu123 jasonlyu123 changed the title Typescript: <svelte:element> href is an unrecognised property <svelte:element> parameter has an 'any' type with an inline handler May 8, 2023
@AlbertMarashi
Copy link
Author

Thanks. Those are working now, but it would be nice to get the typing of events in svelte:elements in inline handlers.

@dummdidumm
Copy link
Member

Minimum reproducible for the events issue:

type EventHandler<E extends Event = Event, T extends EventTarget = Element> =
(event: E & { currentTarget: EventTarget & T}) => any;

type A = {
    'on:click'?: EventHandler<Event,HTMLDivElement>;
}
type B = {
    'on:click'?: EventHandler<Event,HTMLAnchorElement>;
}

const a: A | B = {'on:click': e => e}

@AlbertMarashi
Copy link
Author

Closing this because I think is a valid solution

let tag: 'a' | 'button' = 'a'

@dummdidumm
Copy link
Member

Reopening because of #2003 (comment)

@dummdidumm dummdidumm reopened this Jan 26, 2024
@AlbertMarashi
Copy link
Author

@dummdidumm, this also happens with non-standard HTML elements which are also valid HTML, eg:

<thread-row on:keypress={ e => ... }>

Parameter e implicitly has any type

@jasonlyu123
Copy link
Member

jasonlyu123 commented Jun 24, 2024

It's most likely because there isn't a type definition for the custom element and unrelated to this issue. You'll need to enhance the typing https://svelte.dev/docs/typescript#enhancing-built-in-dom-types. You can use the HTMLAttributes type for the custom element if it inherits an HTML element.

@AlbertMarashi
Copy link
Author

@jasonlyu123

export interface SvelteHTMLElements {
    a: HTMLAnchorAttributes;
    abbr: HTMLAttributes<HTMLElement>;
    ...
    [name: string]: { [name: string]: any }; // this is really annoying
}

This part really messes with everything, why can't the catch all case simply derive from the base HTMLAttributes<HTMLElement> instead of being any because that creates a TONNE of issues with typing everywhere in my app because I use non-standard HTML elements - which are valid HTML..

What is a workaround here?

@AlbertMarashi
Copy link
Author

AlbertMarashi commented Jul 1, 2024

I had to some wack hacky template string to get it to work

	interface SvelteHTMLElements {
		[name: `${string}${
			| "a"
			| "b"
			| "c"
			| "d"
			| "e"
			| "f"
			| "g"
			| "h"
			| "i"
			| "j"
			| "k"
			| "l"
			| "m"
			| "n"
			| "o"
			| "p"
			| "q"
			| "r"
			| "s"
			| "t"
			| "u"
			| "v"
			| "w"
			| "x"
			| "y"
			| "z"}`,
		]: HTMLAttributes<HTMLElement>
	}

@AlbertMarashi
Copy link
Author

AlbertMarashi commented Jul 1, 2024

It's most likely because there isn't a type definition for the custom element and unrelated to this issue. You'll need to enhance the typing https://svelte.dev/docs/typescript#enhancing-built-in-dom-types. You can use the HTMLAttributes type for the custom element if it inherits an HTML element.

I'm not using "custom elements", i'm just using non-standard HTML elements which are also valid HTML, why can't they by default derive their fields and options off HTMLAttributes<HTMLElement>?

export interface SvelteHTMLElements {
    a: HTMLAnchorAttributes;
    abbr: HTMLAttributes<HTMLElement>;
    ...
-   [name: string]: { [name: string]: any };
+   [name: string]: HTMLAttributes<HTMLElement>;
}

I believe this should be updated in the svelte code to be like so

@jasonlyu123
Copy link
Member

That won't work for SVG elements.

@AlbertMarashi
Copy link
Author

@jasonlyu123 yeah with my workaround, sure, but I don't understand why the fallback case shouldn't be HTMLAttributes<HTMLElement> instead of { [name: string]: any } which creates a tonne of parameter has an 'any' type issues across the app when I use valid but non-standard HTML elements

@jasonlyu123
Copy link
Member

No. What I meant is that HTMLAttributes<HTMLElement> won't work for SVG. SVG elements have very different attributes.

@AlbertMarashi
Copy link
Author

@jasonlyu123, why wouldn't SVG Elements have their own key in SvelteHTMLElements which would take precedence?

@jasonlyu123
Copy link
Member

The [name: string] is the part for all the rest. that may include SVG. The known SVG elements are listed. If you want non-standard HTML elements to be typed other people might want non-standard SVG to be typed. And since they're all unsupported the name is unknown and can't be written out to take precedence.

@AlbertMarashi
Copy link
Author

image

This is extremely annoying and I feel like the correct behavior in this scenario is to default to HTMLElement because that's how browsers treat it regardless.

image

As you can see here, on the MDN docs SVG elements still extend from HTML elements, and inherit their interface & properties.

So I think turning them to HTMLAttributes<HTMLElement> still makes sense

@dummdidumm
Copy link
Member

They don't extend from HTML elements, the extend from elements. Very different.
The solution for this is to type your own, as explained here: https://svelte.dev/docs/typescript#enhancing-built-in-dom-types

@AlbertMarashi
Copy link
Author

AlbertMarashi commented Jul 1, 2024

@dummdidumm does it make sense then to do:

interface SvelteHTMLElements {
  [name: string]: HTMLAttributes<Element>
  // or
  [name: string]: HTMLAttributes<Element> & { [key: string]: any }
}

@dummdidumm
Copy link
Member

dummdidumm commented Jul 1, 2024

Element is not necessarily a HTMLElement, as such HTMLAttributes is wrong, because that's for everything that's from HTMLElement, not Element

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants