Svelte - Extend standard html elements with typescript
Asked Answered
H

1

11

I would like to define my custom component and specify which kind of "standard component" I would to extend.

This to consume VSCode intellisense for all standard attributes of the extended component without re-define all attributes.

This is what I would to do:

<script lang="ts">
    // Error: Cannot redeclare block-scoped variable '$$props'
    export let $$props: svelte.JSX.HTMLAttributes<HTMLButtonElement>;

    // OR

    // Error: Cannot redeclare block-scoped variable '$$restProps'
    export let $$restProps: svelte.JSX.HTMLAttributes<HTMLButtonElement>;

    export let myCustomProp: string;
</script>

<button {...$$restProps}>{myCustomProp}<slot /></button>

To explain better what I would like to do, I post the same case in React with Typescript:

import React from 'react';

type Props = {
  myCustomProp: string;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
export default function ({ myCustomProp, ...rest }: Props) {
  return (
    <button {...rest}>
      {myCustomProp}
      {rest.children}
    </button>
  );
}
Holohedral answered 5/4, 2021 at 20:21 Comment(2)
I had a similar kind of issue, maybe the discussion on github will help you: github.com/sveltejs/svelte/issues/6067Touristy
Thanks, same needs. No solutions for nowHolohedral
M
11

Use the svelte/elements to provide an interface $$Props that extends the specific HTML element you want to type.

Button.svelte:

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

    interface $$Props extends HTMLButtonAttributes {
      myCustomProp: string
    }

    export let myCustomProp: string
</script>

<button {...$$restProps}>
  {myCustomProp}
  <slot />
</button>

+page.svelte:

<script lang="ts">
  import Button from './Button.svelte'

  let disabled = false
</script>

<Button myCustomProp='foo' {disabled}>Click Me</Button>

EDIT: If you are dealing with more complex types you could us the typing you defined in $$Props in your exported props:

export let myCustomProp: $$Props["myCustomProp"]
Multilateral answered 7/4, 2023 at 19:14 Comment(5)
Is this really the best way to do this? In this example you have duplicated type definitions, e.g you define myCustomProp inside the interface, and then again you must export it with type defintion from the script tagFed
Is it the best way? I'm not sure, but it appears to be the only way to do it from what I've seen, that said you could define the type and then use it for both definitions if you had a more complex type scenario. If you know a better way let me know :)Multilateral
github.com/sveltejs/language-tools/issues/2016 Opened an Issue about this , DX can definetly be improvedFed
FYI: it is important for the type import to be declared exactly as shown. import {type HTMLButtonAttributes} ... results in error: [vite] Internal server error: No known conditions for "./elements" specifier in "svelte" packageChibcha
In Svelte v5 we won't need to do this anymore and can just type the $props rune, thankfully!Multilateral

© 2022 - 2024 — McMap. All rights reserved.