Javascript function parameter annotation

Hello, I am struggling to correctly annotate a function that should accept an HTMLElement or any subtype of it.


For instance, if I define the function:

@param {HTMLElement} target
function foo(target) { ...}

And have a value of type HTMLInputElement:

/** @type {HTMLInputElement} */ const myInput = document.createElement('input');

When I try to pass myInput to foo, I get "Argument type HTMLInputElement is not assignable to parameter type HTMLElement".

I have also tried to declare the function with a constrained template:

@template {HTMLElement} E
@param {E} target

But then I still get a type mismatch: "Argument type HTMLInputElement is not assignable to parameter type E".

I tried going through Closure Compiler's documentation and check Typescript's types definitions to see if I was missing anything, but I don't know how to get this typing annotation right.
I looked at YouTrack as well, but the most similar issue that I found there was about assigning the return of document.createElement to a variable of a specific type. And it seems to be fixed already.

In my perception, if a function expects a certain type, it should accept any type that extends it as well.
Any help with this situation?


What IDEA version do you work with? Your first solution should be fine, and it works for me - I don't see any errors reported in 2019.2.1:

@param {HTMLElement} target
function foo(target) { }

/** @type {HTMLInputElement} */
const myInput = document.createElement('input');


Hello Elena,

Thank you for the quick answer.

My current IDEA version is 2019.2.2


Considering your reply, I did a double check and the noticed that this indeed wasn't the entire scenario that's leading to the type mismatch.

My variable isn't actually typed statically, its type is inferred from a dynamic type cast, a minimal case which leads to the type mismatch is like the following:

@template T
@param {*} target
@param {{prototype: T, new(): T}} type
@return {T}
export function cast(target, type) {
return /** @type {T} */(target);

const myInput = cast(document.createElement('input'), HTMLInputElement);

This isn't the actual code I'm using, nor I use it in such a simplistic way, it's really a minimal scenario to illustrate how I get the type mismatch. But after myInput is assigned through this cast, IDEA says that it is of type HTMLInputElement, but then gives a type mismatch.


No type mismatch errors are reported for me when using your example:



Could it be some setting that I'm using then?

Here's the inspection message I get:



Can you recreate it in a new project?


No, but I get a validation error on the cast:



I can see it too; why do you need it, BTW? Return type is taken from @return {T}, the is no need in additional casting


Oh, yes... That's right. Maybe it was reminiscent from some previous iteration of my code. I dropped this explicit cast.

Since the validation error doesn't happen on a clean project, I tried moving the .idea folder to another location and reopen the project folder to create a clean project, yet the same message appeared after IDEA indexed the files.


>yet the same message appeared after IDEA indexed the files

Must be smth specific to your project code/dependencies...


I'm gonna dig through the project and run some tests to see if I can find the cause then...

Thanks for the help for now.


I'd like to point out that I discovered the source of my struggle, although I don't understand why IDEA was reacting this way.
At another point in my project's directory structure, I had a cloned copy of immutable-js's source direct from its github directory. As soon as I deleted the "type-definitions" folder, the type mismatch message went away.


Please sign in to leave a comment.