TypeScript with querySelector issues

I’m late to TypeScript, so I’m converting some legacy code to help me learn about it. I’ve come across a few situations that benefit from further investigation.

One of them is when querySelector results in typescript issues.

    const el = document.querySelector("#craftweight");
    el.innerHTML = num;
 // ^^ Object is possibly 'null'.

One possible way to deal with that is to use explicit typecasting to say that el is an HTMLElement

    const el = document.querySelector("#craftweight") as HTMLElement;
    el.innerHTML = num;

Which fixes the problem, but we’re told at Clean DOM Queries that a much cleaner solution is to use a type-argument instead:

The trouble is that we’re left with the same possible null issue:

    const el = document.querySelector<HTMLElement>("#craftweight");
    el.innerHTML = num;
 // ^^ Object is possibly 'null'.

Others recommend casting all of it:

But TypeScript hates that:

    const el = <HTMLElement>document.querySelector("#craftweight");
 // Type assertion using the '<>' syntax is forbidden. Use the 'as' syntax instead.
    el.innerHTML = num;

And we go back around in circles to explicit typecasting instead.

Does TypeScript have an official best-practice in this regard?
Or failing that, what do you think is the best TypeScript solution for this situation?

Hey @Paul_Wilkins, you can use the non-null assertion operator ! here:

const el = document.querySelector('#craftweight')!
el.innerHTML = 'foo'
// Or:
document.querySelector('#craftweight')!.innerHTML = 'bar'
2 Likes

Somehow it doesn’t seem right to have null checking enabled, and then explicitly tell it to ignore that each time. Is that what’s happening here?

Well you can always actually check if el !== null in front, so TS won’t complain either… but oh well… ^^

It’s not about getting TS to not complain. I’m just wanting to understand the better approach, and I think that I’ve found it.

On further thinking about the matter, the Clean DOM Queries article is giving good advice to use a type argument.

    const el = document.querySelector<HTMLElement>("#craftweight");
    el.innerHTML = num;
 // ^^ Object is possibly 'null'.

I have come to realize that typescript isn’t supposed to protect you from null situations, but instead helps by giving you good and clear warnings about such issues upfront.

Because of that, further improvement is needed to the code to suitably deal with the potentially null situation. In this case I want it to be explicitly noisy when this situation occurs.

    const el = document.querySelector<HTMLElement>("#craftweight");
    if (!el) {
        throw new ReferenceError("Craft weight section not found.");
    }
    el.innerHTML = num;

And the code is now somewhat more self-documenting when the error occurs too.