Problem:
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?
Solution:
This is the JSDoc @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.