Right Typescript type for on:change handler in Svelte
Asked Answered
D

3

9

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?

Dail answered 22/5, 2022 at 17:17 Comment(0)
E
21

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.

Externalism answered 22/5, 2022 at 18:28 Comment(0)
A
2

I did this in an input type file:

// added this interface
interface FormEventHandler<T> {
    target: EventTarget | null;
}

// then in the function
const onChangeFile = async (event: FormEventHandler<HTMLInputElement>) => {
    const target = event.target as HTMLInputElement;
    // your code
}
Affrica answered 10/10, 2022 at 18:58 Comment(0)
P
0

A convenient option is to use ChangeEventHandler:

const pathChanged: ChangeEventHandler<HTMLSelectElement> = (event) => {
  console.log(event.currentTarget)
}

This will correctly type event, event.target and event.currentTarget (use it in case the event bubbles up).

See the difference between target and currentTarget on MDN.

Petepetechia answered 23/8 at 12:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.