Rather than using a type assertion, type guard, or any
to work around the issue, a more elegant solution would be to use generics to indicate the type of element you're selecting.
Unfortunately, getElementsByName
is not generic, but querySelector
and querySelectorAll
are. (querySelector
and querySelectorAll
are also far more flexible, and so might be preferable in most cases.)
If you pass a tag name alone into querySelector
or querySelectorAll
, it will automatically be typed properly due to the following line in lib.dom.d.ts
:
querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
For example, to select the first script tag on the page, as in your question, you can do:
const script = document.querySelector('script')!;
And that's it - TypeScript can now infer that script
is now an HTMLScriptElement
.
Use querySelector
when you need to select a single element. If you need to select multiple elements, use querySelectorAll
. For example:
document.querySelectorAll('script')
results in a type of NodeListOf<HTMLScriptElement>
.
If you need a more complicated selector, you can pass a type parameter to indicate the type of the element you're going to select. For example:
const ageInput = document.querySelector<HTMLInputElement>('form input[name="age"]')!;
results in ageInput
being typed as an HTMLInputElement
.