Svelte custom event on svelte typescript
Asked Answered
G

7

33

I'm using clickOutside directive on my svelte-typescript project and I'm getting this error when I assign custom event to the related element

Type '{ class: string; onclick_outside: () => boolean; }' is not assignable to type 'HTMLProps<HTMLDivElement>'.
  Property 'onclick_outside' does not exist on type 'HTMLProps<HTMLDivElement>'

here's a snippet of my code

{#if profileToolbar}
<div
    transition:fly={{ y: -20, duration: 300 }}
    use:clickOutside={profileToolbarContainer}
    on:click_outside={() => (profileToolbar = !profileToolbar)}
    class="origin-top-right absolute right-0 mt-2 w-48 rounded-md
    shadow-lg z-10 shadow-md">

this is the clickOutside directive that I'm using currently https://svelte.dev/repl/0ace7a508bd843b798ae599940a91783?version=3.16.7

I'm new to typescript so I don't really know where to start with my google search, anyone knows how to tackle this issue? thanks for your help

Greylag answered 30/9, 2020 at 4:59 Comment(0)
L
16

Ok, so existing answers did work only partly for me. Given that the clickOutside action fires a custom event named click_outside i arrive at following solution:

declare namespace svelte.JSX {
    interface HTMLProps<T> {
        onclick_outside?: (e: CustomEvent) => void;
    }
}
Lamothe answered 19/2, 2021 at 9:52 Comment(1)
That's the only one actually working, should be marked as answerDesuetude
H
34

According to the doc, you can create a .d.ts file in your project somewhere. And put inside that file the following:

declare namespace svelte.JSX {
  interface HTMLAttributes<T> {
    onclick_outside: () => void
  }
}

Please read the doc for more detail.

Harquebusier answered 30/9, 2020 at 6:12 Comment(6)
Works perfectly!, i just need to change it to interface HTMLProps, thanks for the help and the advice man, i'm aware that svelte typescript is still new, but unfortunately i'm not the one making the decision atm, but i'll make sure to remember your wordsGreylag
To hackape: I know this is a little off topic, but could you share some of the other inconveniences you experienced while using Svelte with TS? I'm one of the maintainers in that area and feedback like this is really valuable (because it's rare).Pectoral
@Pectoral I know bridging the two is not easy, so kudos to the work! But sorry I don’t have much to share cus it was more than half a year ago and I don’t remember much about specific things. I can only remember the general impression about the experience was acceptable, but not totally satisfying. At the end of day I thought to myself better just keep the TS things in .ts file as much as possible and import into .svelte file to lessen the melange and ignore warnings. Later on I switch back to the comfort world of react 😅Harquebusier
I was trying to port the svelte repl into vscode extension, but got interrupted then dropped it halfway. I can find time to dust off and refresh my memory. If I have anything worth sharing I’ll get back to you.Harquebusier
Thanks for the quick response! Things should be better now half a year later, but I agree that there are still some rough edges. About your REPL: In case you only want the "show compiled output" behavior of the REPL, that is now possible through the Svelte for VS Code extension. Command is "Svelte: Show Compiled Code".Pectoral
Ah okay. I want the preview feature too. Are you maintainer of the vscode extension?Harquebusier
C
18

Update 7/23/23

New SvelteKit requires this:

Here is my src/app.d.ts file.

// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
    namespace App {
        // interface Error {}
        // interface Locals {}
        // interface PageData {}
        // interface Platform {}
    }

    declare namespace svelteHTML {
        interface HTMLAttributes<T> {
            'on:clickOutside'?: CompositionEventHandler<T>;
        }
    }
}

export { };

J

Chud answered 30/1, 2023 at 3:0 Comment(3)
For those looking at this answer: A gotcha in this new format is that the property includes the colon : in the property name. So on:clickOutside instead of onclickOutsideDeferred
My custom event and class is called clickOutside, so it works for me.Chud
worked perfectly @sveltejs/kit": "^2.0.0",Bazar
P
16

This declaration worked for me

declare namespace svelte.JSX {
  interface DOMAttributes<T> {
    onclick_outside?: CompositionEventHandler<T>;
  }
}

Don't forget to specify the location of your custom type declarations in tsconfig.json

Praise answered 13/10, 2020 at 9:23 Comment(2)
Where do you put this?Espouse
@Espouse and future readers: SvelteKit comes with a app.d.ts inside the src folder. That's a fine location, also if you're using "plain" Svelte. In comparison, Angular used to generate a typings.d.ts in its src folder for the same purpose.Ordination
L
16

Ok, so existing answers did work only partly for me. Given that the clickOutside action fires a custom event named click_outside i arrive at following solution:

declare namespace svelte.JSX {
    interface HTMLProps<T> {
        onclick_outside?: (e: CustomEvent) => void;
    }
}
Lamothe answered 19/2, 2021 at 9:52 Comment(1)
That's the only one actually working, should be marked as answerDesuetude
D
6

For me the following worked:

declare namespace svelteHTML {
    interface HTMLAttributes<T> {
        "on:click_outside"?: CompositionEventHandler<T>;
    }
}

inside your src/app.d.ts.

based on this

Desmoid answered 4/12, 2022 at 16:44 Comment(0)
W
1

You can now simply do

const dispatch = createEventDispatcher<{
    mounted: { id: string; store: FSStore }
    destroyed: { id: string }
  }>()

onMount(() => {
  dispatch('mounted', {
      id,
      store: fsStore,
  })
  return () => {
      dispatch('destroyed', {
        id,
      })
    }
})

This will then be fully typed:

<Explorer
  on:mounted={onExplorerMount}
  on:destroyed={onExplorerDestroy}
/>

ide preview

Wichman answered 30/1 at 13:15 Comment(0)
P
1

The solution provided by Jonathan did the trick for me, but I found a little improvement that will provide autocomplete for the event.details if you need it:

// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
    namespace App {
        // interface Error {}
        // interface Locals {}
        // interface PageData {}
        // interface PageState {}
        // interface Platform {}
    }

    declare namespace svelteHTML {
        interface HTMLAttributes<T> {
            'on:remove'?: (event: CustomEvent<{ itemId: string }>) => any;
        }
    }
}

export {};

And here’s the official documentation for reference.

Picrate answered 27/7 at 21:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.