最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - JSDoc non-null assertion - Stack Overflow

programmeradmin3浏览0评论

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?

Share Improve this question asked Nov 10, 2022 at 1:19 d-_-bd-_-b 23.2k43 gold badges171 silver badges282 bronze badges 3
  • 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
Add a ment  | 

3 Answers 3

Reset to default 10

After 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

发布评论

评论列表(0)

  1. 暂无评论