Search code examples
typescriptsvelte

Right Typescript type for on:change handler in Svelte


I have this code:

<select class="form-control" on:change={pathChanged}>

The signature for pathChanged is:

function pathChanged(event: { target: HTMLSelectElement }) {

When I run that through tsc using npm run check, I get this error:

Error: Type '(event: { target: HTMLSelectElement; }) => void' is not assignable to type 'FormEventHandler<HTMLSelectElement>'.
  Types of parameters 'event' and 'event' are incompatible.
    Type 'Event & { currentTarget: EventTarget & HTMLSelectElement; }' is not assignable to type '{ target: HTMLSelectElement; }'.
      Types of property 'target' are incompatible.
        Type 'EventTarget | null' is not assignable to type 'HTMLSelectElement'.
          Type 'null' is not assignable to type 'HTMLSelectElement'. (ts)

<select class="form-control" on:change={pathChanged}>

What signature should pathChanged have?


Solution

  • The event target is less specific1 than you would want it to be. In this scenario I usually use a type assertion within the function to work around this.

    function pathChanged(event: Event) {
       const target = event.target as HTMLSelectElement;
       // ...
    }
    

    Though the error states that currentTarget should be typed correctly, so using that should work as well:

    function pathChanged(event: { currentTarget: HTMLSelectElement })
    

    If an event has a more specific type than just Event, e.g. MouseEvent, the types can be combined using &:

    function onMouseUp(event: MouseEvent & { currentTarget: HTMLSelectElement })
    

    1 The reason for that is that most events bubble and the target often can be any element within the element with the handler on it. currentTarget always refers to the element with the handler and thus can be typed definitively.