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?
After looking at the documentation, this can be accomplished 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)
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 outcomes (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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With