DOM basics
| querySelector typed | |
| Narrow the null | |
| Change text | |
| Create elements |
querySelector typed
In the browser, TypeScript knows the page structure through built-in DOM types. querySelector takes a CSS selector and returns the matching element. Pass a generic to state which kind of element is expected, and the result carries the matching type:
const title = document.querySelector<HTMLHeadingElement>("h1");
The generic is the contract with the markup: h1 promises a heading element. Pick the generic that matches the tag, and autocompletion offers exactly the fields that tag owns.
Narrow the null
The element may be missing, so the type always includes null. TypeScript blocks any use before the check, which turns a runtime crash into a compile-time reminder. Narrow with a plain if and throw early, and after that line the value is a real element:
const title = document.querySelector<HTMLHeadingElement>("h1");
if (title === null) {
throw new Error("missing h1");
}
title.textContent = "Hello";
The throw documents the assumption: this page must contain an h1. Readers of the code see the requirement instead of guessing it.
Change text
textContent sets plain text and stays safe with user data: tags inside the string show as text, never as markup. Wrap the read-and-check into a small function, and every title update follows the same safe path:
function setTitle(text: string): void {
const title = document.querySelector<HTMLHeadingElement>("h1");
if (title === null) {
return;
}
title.textContent = text;
}
Here a missing heading means quiet return instead of a crash, which fits optional page parts. Choose throw for required elements and return for optional ones.
Create elements
document.createElement builds a new node of a precise type, and appendChild places it on the page. Set the text before attaching, so readers never see a half-built element:
const item: HTMLLIElement = document.createElement("li");
item.textContent = "Buy milk";
const list = document.querySelector<HTMLUListElement>("ul");
if (list === null) {
throw new Error("missing ul");
}
list.appendChild(item);
createElement with the li tag returns HTMLLIElement directly, so no check is needed for the new node. Only the lookup of the existing list can fail, and the narrow handles that case.
Next: DOM events
Article author: Arthur Isaev