dankobgd
dankobgd

Reputation: 408

Svelte (svelte-kit) type custom action event with typescript

i'm using clickOutside action bellow.

export function clickOutside(node: HTMLElement) {
 function detect({ target }: MouseEvent) {
   if (!node.contains(target as Node)) {
     node.dispatchEvent(new CustomEvent('clickoutside'));
    }
  }
   document.addEventListener('click', detect, { passive: true, capture: true });
   return {
     destroy() {
       document.removeEventListener('click', detect);
    },
  };

This is the error that i still get, when i hover over on:clickoutside={() => {}}

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

I tried this in svelte kit app.d.ts

declare namespace svelte.JSX {
  interface HTMLAttributes<T> {
    clickoutside?: (event: CustomEvent) => void;
  }
}

i tried also HTMLProps<T> and HTMLProps<HTMLDivElement> and many other variations and nothing works. I restarted ts server 25 times so it's not that. this is the link for docs

And no, this is not a duplicate because i literally went through all the other answers and they don't work. like this one: example

Upvotes: 5

Views: 3416

Answers (2)

Mohamad Ojail
Mohamad Ojail

Reputation: 71

I actually just had the same issue, and the docs do offer a great solution. what I did was to modify my app.d.ts to include my interface. here is my action:

import { browser } from '$app/environment'

let iob: IntersectionObserver

const initializeIob = () => {
  console.log('called')

  iob = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      const customEventName = entry.isIntersecting
        ? 'viewportEnter'
        : 'viewportExit'
      entry.target.dispatchEvent(new CustomEvent(customEventName))
    })
  })
}

const viewport = (element: HTMLElement) => {
  if (!iob && browser) initializeIob()

  iob.observe(element)

  return {
    destroy() {
      iob.unobserve(element)
    },
  }
}

export default viewport

you can see that I have viewportEnter that needs to be used with on: in my html element The modified àpp.d.ts` looks like this:

declare global {
  namespace App {
    // interface Error {}
    // interface Locals {}
    // interface PageData {}
    // interface Platform {}
  }
  namespace svelteHTML {
    interface HTMLAttributes<T> {
      'on:viewportEnter'?: (event: CustomEvent) => void
      'on:viewportExit'?: (event: CustomEvent) => void
    }
  }
}

export {}

using it in my html element

<h1
  style="text-align: center;"
  use:viewport
  on:viewportEnter={() => {
    console.log("Entered");
  }}
  on:viewportExit={() => {
    console.log("Exit");
  }}
>
  Hello Actions with Intersection observer!
</h1>

and it works as expected.

Upvotes: 5

brunnerh
brunnerh

Reputation: 184386

The correct current declaration should be:

declare namespace svelteHTML {
    interface HTMLAttributes<T> {
        'on:clickoutside'?: (event: CustomEvent) => void;
    }
}

(Older versions used a different namespace/types, see migration guide.)

Upvotes: 2

Related Questions