avalanche1
avalanche1

Reputation: 3592

Argument of type 'Element' is not assignable to parameter of type 'HTMLElement'

const labelEl: HTMLElement = document.createElement('label')
const isElOfNeededType = (el: HTMLElement): boolean =>
    ["INPUT", "TEXTAREA"].includes(el.tagName);

let result

if (isElOfNeededType(labelEl.nextElementSibling)) {
    result = true
}

Here's my playground: link

  1. Why am I getting this error on labelEl.nextElementSibling?

    Argument of type 'Element' is not assignable to parameter of type 'HTMLElement'

Doesn't HTMLElement extend Element?

2. (not really important, but would be glad if explained) Why does TS playground complains about [ ].includes whereas I've set Config -> Target = esnext ?

Upvotes: 3

Views: 7464

Answers (2)

pekaaw
pekaaw

Reputation: 2607

I also had this issue, even though the context was different.

As previously answered by @Colliere, the problem is that .nextElementSibling is returning an Element, while we often need it as an HTMLElement.

A straightforward solution is change the type to HTMLElement before using it.

In your example you can use type assertion like this:

const labelEl: HTMLElement = document.createElement('label')
const isElOfNeededType = (el: HTMLElement): boolean =>
    ["INPUT", "TEXTAREA"].includes(el.tagName);

let result

if (isElOfNeededType(labelEl.nextElementSibling as HTMLElement)) {
    result = true
}

I used JSDOC, so I had to use JSDOC type casting (note the extra parentheses):

    const nextElementSibling = (
        /** @type {HTMLElement} */
        (labelEl.previousElementSibling)
    );

Upvotes: 1

Collierre
Collierre

Reputation: 956

labelEl.nextElementSibling is of type Element. See the definition in Definitely Typed. So your code is trying to pass an Element where an HTMLElement is required.

As you say, HTMLElement extends Element, but this does mean you can pass an Element in place of an HTMLElement, because the Element may not have properties that an HTMLElement does. You could however pass an HTMLElement where an Element is expected, because an HTMLElement will have all the properties of an Element.

Seeing as you are only interested in the tagName property, which exists on Element I would just change your code to use Element.

const labelEl: HTMLElement = document.createElement('label')
const isElOfNeededType = (el: Element): boolean =>
    ["INPUT", "TEXTAREA"].includes(el.tagName);

let result

if (isElOfNeededType(labelEl.nextElementSibling)) {
    result = true
}

Upvotes: 2

Related Questions