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

Typing Svelte Component Props/Events/Slots [Feedback Thread] #442

Closed
dummdidumm opened this issue Aug 11, 2020 · 117 comments
Closed

Typing Svelte Component Props/Events/Slots [Feedback Thread] #442

dummdidumm opened this issue Aug 11, 2020 · 117 comments
Labels
feature request New feature or request

Comments

@dummdidumm
Copy link
Member

dummdidumm commented Aug 11, 2020

[this is now the feedback thread]

This was implemented according to this RFC. Please provide feedback about using it in this thread.

Original Post

There are several issues about this already (#424, sveltejs/svelte#304, sveltejs/svelte#273, sveltejs/svelte#263), but I wanted to make a consolidated one to have a discussion about the approaches we can take.
Related PR: sveltejs/svelte#437

Note that this issue is NOT about typing a d.ts file, this will come afterwards as a separate issue.

Is your feature request related to a problem? Please describe.
At the moment it is not possible to type the inputs/outputs of a component under certain circumstances:

  • It is not possible to define a generic relationship between props and events/slots (generics)
  • It is not possible to define the events and their types
  • It is not possible to define the slots and their types in a specific way

Describe the solution you'd like
A way to type props/events/slots explicitly.

Proposal: A new reserved interface ComponentDef which, when defined, is used as the public API of the component instead of infering the things from the code.

Example (with comments about what likely is not possible):

<script lang="ts"
   interface ComponentDef<T> { // <-- note that we can use generics as long as they are "defined" through props
      props: {  items: T[]  }
      events: {  itemClick: CustomEvent<T>  }
      slots: { default: { item: T } }
  }

   // generic type T is not usable here. Is that a good solution? Should it be possible?
   // Also: How do we make sure the types match the component definition?
  export items: any[];

   // ...

   // We cannot make sure that the dispatched event and its type are correct. Is that a problem?
   // Maybe enhance the type definitions in the core repo so createEventDispatcher accepts a record of eventname->type?
   dispatch('itemClick', item);
</script>
<!-- ... -->
<slot item={item}> <!-- again, we cannot make sure this actually matches the type definition -->

When someone now uses the component, he will get the correct types from the props/events/slots and also error diagnostics when something is wrong:

<Child
     items="{['a', 'string']}"
     on:itemClick="{event => event.detail === 1 /* ERROR, number not comparable to type string */}"
/>

If this works and is tested a little, we could enhance it with other reserved interfaces like ComponentEvents to only type one of the things.

I'd like to get as much feedback on this as possible because this is likely a big change which might be used broadly. Also, I'd like to have some of the core team members to have a look at this if this looks good to them or introduces something they don't agree with.

@jasonlyu123 @orta @Conduitry @antony @pngwn

@dummdidumm dummdidumm added the feature request New feature or request label Aug 11, 2020
@pngwn
Copy link
Member

pngwn commented Aug 11, 2020

Seems reasonable, there is actually a Svelte issue about being able to inject slots at runtime. sveltejs/svelte#2588 and a PR that implements it sveltejs/svelte#4296, feels like there might be overlap, or at least some opportunity to align the interfaces (if there is any consenus, there are still some outstanding questions with the above PR).

@dummdidumm
Copy link
Member Author

Thanks for the PR link, seems like it's only related in a way to us that we have to type the constructor a bit differently then, but I think this is indendent of the type checking on a template level.

@halfnelson
Copy link
Contributor

interesting.
I wonder if we could do something like

<script lang="ts" generic="T"> 
    type T = unknown
    export let items: T[]
    let item:T = items[0]
</script>
<slot b={item}></slot>

which would strip the type T = unknown during typecheck and instead add it as a generic argument to the component.

//...
render<T>() {
    export let items: T[]
    let item:T = items[0]
}

@dummdidumm
Copy link
Member Author

dummdidumm commented Aug 12, 2020

Good idea about adding it to the render function!

I think we can get the same results with

<script lang="ts">
    interface ComponentDef<T> {
       ...
    } 
    type T = unknown
    export let items: T[]
    let item:T = items[0]
</script>
<slot b={item}></slot>

by extracting the T from the interface definition.

Although with your solution you will have to type less in the case of "I just want a generic relationship between my props and slots", which is nice. On the one hand I'm thinking "yeah we could just add both", on the other hand it feels a little like expanding the API surface too much (you can do the same things in different ways) - not sure.

@shirakaba
Copy link

shirakaba commented Aug 12, 2020

I really don't want to have to write out the interface ComponentDef<T>{ props: {} } and line it up with each one of my exports. Svelte does so well in reducing characters typed compared to React, and this feels like a step backwards. In particular, it requires duplicating the types of every export into the props, which is no fun (and bound to lead to frequent problems).

I like @halfnelson's line of thinking. Exports should be detected as props. I don't know what the module looks like once <script> is transpiled to a module, nor how the Svelte Language Server gets to see it when consuming it from another file, but I'd really hope for it to be possible for exports to just be detected automatically as props.

I have to dash now, but one more thought: As for typing the slot, would JSX generics provide any inspiration?

@shirakaba
Copy link

Another quick one, as I read it in some of the related issues: I've had no end of trouble using JSDoc comments to type things, including the @template option.

While we should keep an open mind to JSDoc (even using JSDoc within the HTML), I must warn that, whether used through WebStorm or VS Code, it is simply not expressive as TypeScript. e.g. it does not implement the true type; I'm sure it doesn't do index types; and if I recall, you can't have a Record<keyof X, any> either. I keep running into walls with it. @template did work, but was pretty limited, too. And I think it works differently well depending on IDE, as well.

@dummdidumm
Copy link
Member Author

Passing the generic type the (jsx)element is a no-go for me because it's not valid svelte template syntax. It should also not be needed since generics are driven by properties, I cannot think of a way to introduce a generic dependent for slots/events only. If they are driven by input properties passing generics to jsx elements is not needed because we can generate svelte2tsx code in such a way that TS will infer it for us.

About the typing overhead: This is correct but would only be needed in situations where you want to use generics and/or ecplicitly type events/slots. In theory, we could infer all of this ourselves, but this feels super hard to implement. Examples of such hard to implement problems are support for advanced slots scenarios like in sveltejs/svelte#263, and to collect all possible component events (which is easy if the user only would use createEventDispatcher, but he could also import a function which wraps createEventDispatcher stuff).

In general I feel that there are many situations where people would want only to define one of those things, but not the others, so maybe it is indeed necessary to provide all the different options to keep the "type less"-spirit of Svelte.

This would mean:

  • ComponentDef is the do-all-in-one-if-you-need-it
  • ComponentEvents is for typing events only
  • ComponentSlots is for typings slots only
  • a construct like <script generic="T"> if you only need generics
  • a combination of ComponentEvents/ComponentSlots/generic="T"

@jasonlyu123
Copy link
Member

jasonlyu123 commented Aug 12, 2020

@shirakaba The JSDoc type support doesn't have to be as feature-rich as a typescript. I doubt a lot of people would type generic components with it. Also because we're using typescript's language service, a lot of the advanced type can be easily imported from a typescript file.

About slot props type-check, I have some hack but don't know if this would lead to good developer experience. If user type component like this:

interface ComponentDef {
      slots: { default: { item: string } }
  }

we can generate a class

class DefaultSlot extends Svelte2TsxComponent<ComponentDef['slots']['default']>{ }

and transform default slot to

<DeafaultSlot />

@joelmukuthu
Copy link

(only chiming in as a user) For me the extra typing is not an issue because I have to do a lot of it anyway while working with TypeScript.

As for the interface vs the generic prop, since there are cases where variables are only exposed to the consumer, it would be better DX to support the prop. But on that note, would it possile to support export type T instead of generic="T"?

@dummdidumm
Copy link
Member Author

This is invalid TS syntax which might confuse people. Also, we would have to do an additional transformation step, which would not be done in case the Svelte component is in a non-compilable-state. In this case the language-tools fall back to what is in the script, which then would have this invalid syntax. So I'm against that.

@joelmukuthu
Copy link

I understand. Not to linger, but is it invalid syntax or more of an "undefined/unknown type" error? I'm asking because I don't know how TypeScript's compiler handles the two cases. I just have reservations against adding a custom attribute to a script tag, especially with a name as generic as "generic" :)

All in all, for me, this is a nice-to-have and perhaps forcing the user to type the exported variables when using the component is a good thing (more readable code).

@dummdidumm
Copy link
Member Author

When you type export type T;, TS will throw a syntax error. Also, how to formulate constraints? export type T extends string; will throw more syntax errors at you. I totally understand your reservation against a custom attribute, but I think it's the least disrupting way. Other ways would be to have reserved type names like T1 or T2 but that is not flexible enough (how to add constraints?).

The alternative would be to type the whole component via ComponentDef, where you can freely add generics, like in the example in the starting post. But this comes at the cost of more typing.

For me it becomes clear from the discussion that people have very different opinions on this and to have more options laid out (ComponentDef, generic props as attributes, only typing ComponentEvents) is the most flexible to make most of them happy, although they introduce different ways of doing the same thing.

@joelmukuthu
Copy link

joelmukuthu commented Aug 26, 2020

I may have missed this but is splitting it up an option?

<script>
  import type { Foo } from './foo';
  export let items: Foo[];
  interface ComponentSlots<T> {}
  interface ComponentEvents<T> {}
</script>

Would that reduce the typing overhead for most cases?

@dummdidumm
Copy link
Member Author

Yes this would be possible.

@dummdidumm dummdidumm pinned this issue Sep 3, 2020
@joelmukuthu
Copy link

@dummdidumm is it possible to work on supporting interface ComponentSlots {} (with or without support for generics) in the meantime? Or would introducing that be contradictory to the things discussed here?

@dummdidumm
Copy link
Member Author

It wouldn't, but before continuing the implementation I first want to write a RFC to get more feedback from the community and the other maintainers on the proposed solution. Once there's an agreement, we will start implementing those things.

@dummdidumm
Copy link
Member Author

@joelmukuthu btw why would you like to have the interface support? We enhanced the type inference for slots, is there a case where it's still not working out for you? If so, I'm curious to hear your case.

@dummdidumm
Copy link
Member Author

I now created a RFC on this topic: sveltejs/rfcs#38
Discussion on the API should continue there.

@joelmukuthu
Copy link

@dummdidumm sorry for the slow response. I've just realised that for my use-case, I do actually need support for generics. Type inference for slots works quite well!

@NickClark
Copy link

This would be huge! I'm currently saddened that using slot properties is always an any.

@dummdidumm
Copy link
Member Author

That's strange, slot typed can be infered quite nicely at this point, if the compont you use is within you project and uses TS, too.

@NickClark
Copy link

Perhaps I'm using the wrong terms here... or hopefully I just did something wrong.

Example of what I wish I could do:

<SelectInput options={myArrayOfObjects} let:option>
   <!-- I wish option here was the correct type */ -->
  {option.myLabelProp}
</SelectInput>

<!-- SelectInput Component -->

<script lang="ts" generic="T">
  export let options: Array<T> = [];
</script>

<div class="select">
  {#each options as option}
    <slot {option} />
  {/each}
</div>

@dummdidumm
Copy link
Member Author

Ok I understand, yes right now this is not possible, so you have to fall back to any[]. If this would allow only string[], your slot would be typed as string, which is what I meant by "type can be infered".

@RamiAwar
Copy link

RamiAwar commented Feb 23, 2021

A nice temporary solution to type checking components I've come across in "Svelte and Sapper in Action" by Mark Volkmann is the use of the React prop-types library alongside $$props.

This is the code for a Todo item for example:

import PropTypes from "prop-types/prop-types";

const propTypes = {
    text: PropTypes.string.isRequired,
    checked: PropTypes.bool,
};

// Interface for Todo items
export interface TodoInterface {
    id: number;
    text: string;
    checked: boolean;
}

PropTypes.checkPropTypes(propTypes, $$props, "prop", "Todo");

While I'm validating the props of Todo and getting errors if something is off, I also want to have an interface for Todo items, so that I can have static type checking in VSCode as well as autocompletions. This is achieved by using the interface I defined above. The obvious and significant downside of this is that I need to have duplicate code here. I can't define an interface from the propTypes object, or vice-versa.

I'm still starting out in javascript so please correct my if any of this is wrong.

I think type checking is a must have for any productive codebase, both static checking and props type checking at runtime.

(Note that the interface would be defined in context='module' so its exportable alongside the component default export, but omitted that part for brevity)

Edit: Have not tried this for anything other than props validation, let me know if it would also work for slots/events!

vnphanquang added a commit to vnphanquang/svelte-put that referenced this issue Oct 17, 2022
fallaciousreasoning added a commit to brave/leo that referenced this issue Nov 14, 2022
This was based on the ideas here sveltejs/language-tools#442 (comment) (search for `absolute bonkers`
@axmad386
Copy link

I am trying to create a component that can either be a button or an anchor tag like so:

<script lang="ts">
	type Element = $$Generic<'button' | 'a'>;

	type $$Props = svelteHTML.IntrinsicElements[Element] & {
		element: Element;
	};

	export let element: Element;
</script>

<svelte:element this={element} class="button" on:click {...$$restProps}>
	<slot />
</svelte:element>

The typing seems to be working properly howvere I am getting this ts error:

Argument of type '{ element: Element; }' is not assignable to parameter of type 'Partial<$$Props>'.ts(2345)

Any idea?

Did you found the solution? I build something similar, lol

@alialaa
Copy link

alialaa commented Nov 30, 2022

@axmad386 it's worked with me after some svelte update. I didn't change anything.

@rossedfort
Copy link

rossedfort commented Dec 5, 2022

In the RFC, it's mentioned that you probably won't use ($$Props) because it's essentially doing the type work twice, however, I think there is a valid use case here that is being missed. As an author of a component library written in Svelte, I'd like for my components to accept any valid HTML attributes and forward them to the HTML Element that the component renders. The way I've decided to implement this matches the way I would in other frameworks, which is typing the component as an extension of an existing interface that encompasses valid HTML Attributes, yet not explicitly defining any of those attributes as props on the Component itself.

<script lang="ts">
  interface $$Props extends svelte.JSX.HTMLAttributes<HTMLButtonElement> {
    error: boolean;
  }

  export let error: boolean;
</script>

<button class:error {...$$restProps}>
  <slot />
</button>
<!-- id and data-bar are forwarded to the <button /> as well as strongly typed -->
<Button error={false} id="foo" data-bar="baz">Click Me</Button>

Because the $$Props interface in my component extends that of the HTMLAttributes for a Button element, users are able to safely pass valid Button Attributes when consuming my component. Also, because the error prop is defined explicitly using export let, it is not contained in $$restProps, so $$restProps can be spread to my <button /> with reasonable type safety. This works great, however, my major complaint is that I have to type my error prop twice - once in my $$Props interface and once in my export let statement. Omitting an explicit type on my export let statement leaves my error identifier as an implicit any, while not including error in my $$Props interface also makes for an improperly typed component.

<script lang="ts">
  interface $$Props extends svelte.JSX.HTMLAttributes<HTMLButtonElement> {
    error: boolean; // error is explicitly typed as boolean to consumers of the component
  }

  export let error; // error is implicitly typed as any within the component
</script>

<button class:error {...$$restProps}>
  <slot />
</button>

Allowing components to safely forward valid HTML Attributes to the HTML Element they render is a fairly common use case amongst component library authors. I would love to see some more robust support for this. Here's how it looks in React for example:

import * as React from 'react';

interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
  error: boolean; // error is explicitly typed as boolean to consumers of the component
}

// error is explicitly typed as boolean within the component
const Button: React.FC<ButtonProps> = ({ error, children, ...restProps }) => (
  <button className={error && 'error'} {...restProps}>
    {children}
  </button>
);

export default Button;

To summarize, I would love a way to simultaneously define and type a Svelte Component's external API and internal props en masse without duplicating a type.

Thanks.

@crazyursus92
Copy link

crazyursus92 commented Dec 13, 2022

Hi everyone! I do this by this way

<script lang="ts">
interface $$Props extends svelte.JSX.HTMLAttributes<HTMLButtonElement> {
    error: boolean; // error is explicitly typed as boolean to consumers of the component
  }

let  {error, ...restProps} = $$props as $$Props;
</script>

<button class:error {...restProps}>
  <slot />
</button>

Of corse, it is tricky, because we are casting SvelteAllProps to $$Props, but it close to safe way to do it.

@dummdidumm
Copy link
Member Author

How to extend prop types from HTML elements

For everyone who wants to create a wrapper component around a certain HTML element and wants a way to type "this component accepts all properties of X", here's how you do it as of Svelte version 3.55:

<script lang="ts">
  import type { HTMLButtonAttributes } from 'svelte/elements';
  interface $$Props extends HTMLButtonAttributes {
    error: boolean; // your own additional typings
  }

  export let error: boolean;
  // ...
</script>

<!-- ... -->
<button>
  <slot />
</button>

Svelte version 3.55 comes with a new svelte/elements export which contains typings for all regular HTML elements. It will also power the next major version of svelte-check.

@brunnerh
Copy link
Member

brunnerh commented Jan 8, 2023

Regarding the HTML props feature, it would be nice if duplication of all the custom props could be avoided.
I would suggest adding a generated type for that, e.g. $$ExportedProps, so you can do:

<script lang="ts">
  import type { HTMLButtonAttributes } from 'svelte/elements';

  interface $$Props extends HTMLButtonAttributes, $$ExportedProps {
    // `error` not specified explicitly
  }

  export let error: boolean;
</script>

Or just:

type $$Props = HTMLButtonAttributes & $$ExportedProps;

@tjmgregory
Copy link

@brunnerh Either the latter would be my vote, or, if we could simply infer the HTML element we're passing the $$restProps to, i.e.

<!-- Image.svelte -->

<img {...$$restProps} />

<!-- App.svelte -->
<script>
import Image from './image.svelte'
</script>

<!-- Type-safe, the following would error as missing a `src` -->
<Image />

Side benefit of forcing the $$restProps to be used in a single place is the compiler could then elevate other concerns like A11y: <img> element should have an alt attribute to the caller of <Image>

@brunnerh
Copy link
Member

brunnerh commented Jan 9, 2023

It's not either or; once the type is there, you can use it both ways, that's just TS.

You would usually only use the interface then if you actually want to add additional props that are not explicitly exported (e.g. access happens via $$props/$$restProps).

@tjmgregory
Copy link

tjmgregory commented Jan 9, 2023

Not necessarily, only if you want to add props. Example without wanting to add props I can think of is an UnstyledLink:

<!-- UnstyledLink.svelte -->

<a {...$$restProps}><slot /></a>

<style>
  a {
    text-decoration: none;
    color: inherit;
  }
</style>

I'd then like the caller to automatically have to supply an href attribute, as Svelte can infer that UnstyledLink's props are that of <a>

@brunnerh
Copy link
Member

brunnerh commented Jan 9, 2023

You misunderstood what I was saying. You said:

Either the latter would be my vote, or, ...

My point was, it's not either "the former" or "the latter", but that both can be used. Of course my suggestion does not include the automatic inference you detail after that. So your statement might as well have been:

Either that, or, ...

Also, it probably would not hurt to have both the $$ExportedProps type and the automatic inference. So you would just specify $$Props when you need some more customization.

@fnimick
Copy link

fnimick commented Feb 4, 2023

Is there a way to have an optional added prop with the $$Props interface when extending an HTML element?

My example:

<script lang="ts">
  import type { HTMLInputAttributes } from "svelte/elements";

  interface $$Props extends HTMLInputAttributes {
    label?: string | undefined;
  }

  export let label: string | undefined;
</script>

This fails with error:

Argument of type '$$Props' is not assignable to parameter of type '{ label: string | undefined; }'.
  Property 'label' is optional in type '$$Props' but required in type '{ label: string | undefined; }'.

Is there a recommended way to provide an optional prop and type it in $$Props? Marking it as required and allowing undefined causes TypeErrors when the component is used and the optional prop is not provided.

EDIT: I was able to fix this by defining the prop as follows:

export let label: string | undefined = undefined;

Leaving the question above to help others who might run into this.

@TGlide
Copy link
Member

TGlide commented Apr 3, 2023

Types like this don't seem to be working either:

type BaseProps<T extends HTMLElement = HTMLElement> = HTMLAttributes<T> & {
	[key: `data-${string}`]: string | boolean | undefined;
};

@GauBen
Copy link
Contributor

GauBen commented May 17, 2023

I commented on the RFC because it was more recent, but this thread is where I should have posted in the first place. Sorry for the spam for people in both threads.

I use generics to have events typed using a children component's props, it looks roughly like this:

<script lang="ts">
  type Entry = $$Generic<
    ComponentProps<EntryComponent> & {
      id: string;
    }
  >;
  
  export let entries: Entry[];
  
  const dispatch = createEventDispatcher<{
    click: Entry;
  }>();
</script>

{#each entries as entry (entry.id)}
  <EntryComponent {...entry} on:click={() => dispatch('click', entry)}  />
{/each}

I don't know how much of a pattern/anti-pattern this is, but it allows for complete type inference without hand-maintained types

@Nick-Mazuk
Copy link

As far as I can tell, the current $$Generics syntax cannot emulate the <const T extends ...> allowed by normal functions in TypeScript.

const getKeys = <const T extends { key: string }>(items: T[]): T['key'] => {
  return items[0].key
};

// keys has type type "foo" | "bar"
const keys = getKeys([{ key: 'foo' }, { key: 'bar' }]);

// keys2 has type "baz" | "qux"
const keys2 = getKeys([{ key: 'bar' }, { key: 'qux' }]);

Playground

This means it's impossible to strongly type one prop with the values of another, complex prop.

@dummdidumm
Copy link
Member Author

That's correct - for this reason and a couple of others we will probably switch to another way of defining generics: #2020

@paul-williams-bringmeister
Copy link

paul-williams-bringmeister commented Jun 20, 2023

HI - I'm a bit confused why this doesn't exist in the documentation. This seems to be a supported feature of sveltekit (the compiler can certainly tell that I'm typing my slots, and gives type errors / warnings etc.), but it's nowhere to be found on the website.

Using:

@sveltejs/kit: 1.20.4
svelte: 3.59.1

I eventually found this functionality detailed at this link, but it should definitely be in the official documentation.

@dummdidumm
Copy link
Member Author

It's experimental still, which is why it's not in the official documentation yet - but there will be a link to the RFC on the site, soon

@paul-williams-bringmeister

@dummdidumm awesome, thank you!

@GauBen
Copy link
Contributor

GauBen commented Jun 27, 2023

Svelte v4 breaks the pattern I described above:

<script lang="ts" context="module">
  type MinimalThing = {
    name: string;
  };
</script>

<script lang="ts" generics="Thing extends MinimalThing">
  import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher<{
    click: Thing;
  }>();

  export let thing: Thing;
</script>

<button on:click={() => dispatch('click', thing)}>{thing.name}</button>
                            <!-- ~~~~~~~~~~~~~~ -->
Argument of type '["click", Thing]' is not assignable to parameter of type
'[Thing] extends [never]
	? [type: "click", parameter?: null | undefined, options?: DispatchOptions | undefined]
	: null extends Thing
	? [type: "click", parameter?: Thing | undefined, options?: DispatchOptions | undefined]
	: undefined extends Thing
	? [type: ...] : [type: ...]'

I don't know how to fix this

Edit: tracked in sveltejs/svelte#8860 and microsoft/TypeScript#54806

0x088730 pushed a commit to 0x088730/svelte_three.js that referenced this issue Jul 18, 2023
This is possible now - cool! see sveltejs/language-tools#442 (comment)

'mat' shorthand attribute will give us proper intellisense (props list) for the assigned 'material'!
@brunnerh
Copy link
Member

brunnerh commented Jul 31, 2023

There appears to be an issue with angle brackets in the generics attribute:

<script lang="ts" generics="T extends Record<string, unknown>">

error TS1002: Unterminated string literal.

Can be worked around by extracting the base type as a type alias to a context="module" script.

@dummdidumm
Copy link
Member Author

<script lang="ts" generics="Foo, Bar extends Record<string, unknown>">

is the official forward here, and docs will be on the new Svelte site soon, therefore closing.

@dummdidumm dummdidumm unpinned this issue May 22, 2024
@skylerknight
Copy link

@axmad386

Here is a way to create a component that can be a button or an anchor tag. (Or any other element)

<script lang="ts" generics="E extends keyof svelteHTML.IntrinsicElements = 'button'">
  import type { Snippet } from 'svelte';
  import type { SvelteHTMLElements } from 'svelte/elements';

  type Props<E extends keyof svelteHTML.IntrinsicElements> = {
    as: E;
    children: Snippet;
  } & SvelteHTMLElements[E];

  let { as, children, ...rest }: Props<E> = $props();
</script>

<svelte:element this={as} {...rest}>
  {@render children()}
</svelte:element>

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

No branches or pull requests