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?

0
11 comments

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');

foo(myInput)
0

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.

0

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

 

0

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

Here's the inspection message I get:

 

0

Can you recreate it in a new project?

0

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

 

0

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

0

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.

0

>yet the same message appeared after IDEA indexed the files

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

0

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.

1

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.

0

Please sign in to leave a comment.