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
This is the JSDoc @param definition to use:
/** @param {Event & {currentTarget: EventTarget & HTMLInputElement} & {target: HTMLInputElement} & InputEvent} event */
For explanation see bottom of question.
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 exampleconst 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:
► An alternative function expression syntax:
► And lastly, if the event handler is a function declaration: