skip to Main Content

I’m trying to type an event that I receive from a Svelte-managed input element, but TypeScript tells me that my JSDoc type is incompatible with what I receive from the on:input. In my page code I have an input field with the following handler:

<input id="description" on:input={handleInput}

And in JavaScript I have:

/** @param {InputEvent & { target: HTMLInputElement}} event */
const handleInput = (event) => {
  const fullInput = event.target.value;
  const singleChar = event.data;
  const cursorPosition = event.target.selectionStart;
  // ...

In handleInput() the types are recognised correctly. But TypeScript shows this error on on:input in the HTML:

Type '(event: InputEvent & {    target: HTMLInputElement;}) => void' is not assignable to type 'FormEventHandler<HTMLInputElement>'.
  Types of parameters 'event' and 'event' are incompatible.
    Type 'Event & { currentTarget: EventTarget & HTMLInputElement; }' is not assignable to type 'InputEvent & { target: HTMLInputElement; }'.
      Type 'Event & { currentTarget: EventTarget & HTMLInputElement; }' is missing the following properties from type 'InputEvent': data, dataTransfer, inputType, isComposing, and 5 more.js(2322)

Why are these types incompatible and what can I do about this?

Edit: answer to my question below.

This is the param definition to use:

/** @param {Event & {currentTarget: EventTarget & HTMLInputElement} & {target: HTMLInputElement} & InputEvent} event */

Explanation:
Just to see the type change on:input to on:input={(e)=> e } and hover over e. You will get the exact type that is expected (copy/paste-ready for JSDoc @param).

In this case it was: {Event & {currentTarget: EventTarget & HTMLInputElement}

This solves the TS error on on:input, but it creates TS errors on:

  const fullInput = event.target.value;
  const singleChar = event.data;
  const cursorPosition = event.target.selectionStart;

Because .data and .target is not a property on Event, but on InputEvent. See explanation why Svelte is not using InputEvent here.
And .target should be typed as HTMLInputElement (like .currentTarget)
By adding & {target: HTMLInputElement} & InputEvent you can add these types and TS doesn’t complain any more. Not sure if this is good practice though.

Hope this helps others. Thank you Mike ‘Pomax’ Kamermans and jonrsharpe and the Svelte Discord channel.

2

Answers


  1. Chosen as BEST ANSWER

    This is the JSDoc @param definition to use:

    /** @param {Event & {currentTarget: EventTarget & HTMLInputElement} & {target: HTMLInputElement} & InputEvent} event */

    For explanation see bottom of question.


  2. A typical JSDoc line for an oninput event in JavaScript can be done in three ways that I can think of. Most importantly, if you are saving your function to a variable (for example const func = () => "hello", a.k.a. a function expression), you cannot use the JSDoc @param keyword. Instead you must use the special JSDoc function expression syntax as shown in the following examples.

    ► If the event handler is a function expression:

    /**@type{(event:Event)=>void}*/
    const handleInput = event => {
      // do stuff...
    };
    

    ► An alternative function expression syntax:

    /**@type{function(Event):void}*/
    const handleInput = event => {
      // do stuff...
    };
    

    ► And lastly, if the event handler is a function declaration:

    /**
     * @param {Event} event
     * @return void
     */
    function handleInput(event) {
      // do stuff...
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search