In javascript, using JSDoc, I'm querying for an element on the page:
// @ts-check
/** @type {HTMLInputElement} */
const element = document.getElementById('checkbox');
But I get the warning:
Type 'HTMLElement | null' is not assignable to type 'HTMLInputElement'. Type 'null' is not assignable to type 'HTMLInputElement'.ts(2322)
Is there a way to assert this type as not null, like you would do in typescript with the !
operator?
In javascript, using JSDoc, I'm querying for an element on the page:
// @ts-check
/** @type {HTMLInputElement} */
const element = document.getElementById('checkbox');
But I get the warning:
Type 'HTMLElement | null' is not assignable to type 'HTMLInputElement'. Type 'null' is not assignable to type 'HTMLInputElement'.ts(2322)
Is there a way to assert this type as not null, like you would do in typescript with the !
operator?
-
Facing the same problem, usually I add
@ts-ignore
after/** @type {...} */
doc block. Looking for a better solution too. – Yusuf T. Commented Nov 10, 2022 at 7:00 - I may be reproducing the error incorrectly... I took your code, added it to myself and shows me the type of the HTMLInputElement variable and does not swear at the mismatch of types – SwaD Commented Nov 17, 2022 at 19:23
- You can cast the type: const element = document.getElementById('checkbox') as HTMLInputElement – danielRICADO Commented Apr 23, 2024 at 3:56
3 Answers
Reset to default 10After looking at the documentation, this can be acplished using inline casting. So in your case, the correct code should be like this:
// @ts-check
const element = /** @type {HTMLInputElement} */ (document.getElementById('checkbox'));
Also, make sure that after the /** @type {...} */
annotation you need to wrap your code using parentheses.
Here's a better way so you don't have to always write out the exact type of the value, more like the convenience of the non-null operator in TS:
/**
* In lieu of writing in TypeScript and having the convenient non-null assertion
* operator (!), this helper function allows asserting that something is not
* null or undefined without having to write a JSDoc type cast that has to
* explicitly know the non-null type (which is error prone).
*
* For example, insgtead of having to write this:
*
* ```js
* const value = /** @type {SomeNullableType} */(possiblyNullValue)
* ```
*
* we can write this:
*
* ```js
* const value = NonNull(possiblyNullValue)
* ```
*
* @template {any} T
* @param {T} item
*/
function NonNull(item) {
if (item === null || item === undefined) throw 'item is null or undefined'
return item
}
In this example, the type of div
will be HTMLDivElement
, not HTMLDivElement | null
, as desired (plus it will throw if you are actually wrong, which may be even more desirable!):
const div = NonNull(document.querySelector('div'))
Screenshot of the type awareness in VS Code with and without using NonNull
:
You could also do this, which will not do a runtime check, but will force it to be non-nullable (more like the non-null !
operator):
/**
* @template {any} T
* @param {T} item - Item you want to strip nullable from.
* @returns {NonNullable<T>}
*/
function NonNull(item) {
return /** @type {NonNullable<T>} */(item)
}
/** @type {number | null} */
const foo = 123
// type of `test` is `number`
const test = NonNull(foo)
Words of advice
Go for the one that has the conditional check. The second one, that does a type cast, can result in undefined
silently flowing through your program without any runtime error, manifesting in the wrong outes (f.e. something different is rendered on screen, your server sends back something else to a client, or etcetera).
If you expect something to not be null, it is safer to actually expect that in your code.
If you think the conditional check is going to ruin your performance (and that the difference will actually matter), you may be wrong. Don't give up a good thing unless something significantly worse actually exists and giving up the good thing to solve it is actually worth it.
As of the current version of JSDoc you can just use the same ! operator as in typescript.
// @ts-check
/** @type {!HTMLInputElement} */
const element = document.getElementById('checkbox');
See the docs under Non-nullable Type: https://jsdoc.app/tags-type