question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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

See original GitHub issue

[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

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:26
  • Comments:100 (46 by maintainers)

github_iconTop GitHub Comments

23reactions
NickClarkcommented, Nov 12, 2020

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>
11reactions
halfnelsoncommented, Aug 12, 2020

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]
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Typing Components in Svelte - Viget
Built-in tools for typing your Svelte components. ... exist as standalone files that declare an interface of props, slots, and events.
Read more >
Type-safe Mutual Exclusivity in Svelte Component Props
Mutual exclusivity is an extremely common logical pattern in programming. Requests can succeed, or they can fail. A user can be logged in, ......
Read more >
Docs • Svelte
Svelte uses the export keyword to mark a variable declaration as a property or prop, which means it becomes accessible to consumers of...
Read more >
Creating a Svelte Tabs component with Slot props
TabWrapper holds other child components, and TabHead wraps head items with a ul tag. TabHeadItem holds a li tag and a on:click event...
Read more >
Design Patterns for Building Reusable Svelte Components
The interface accepts three generic parameters. Use the first to type component props, the second for events, and the third for slots.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found