Якщо ви думали, що під типізацію підпадають тільки дефолтні змінні, класи, функції, то ні - типізується все, включно з HTML DOM елементами. Коли ви використовуєте DOM звернення, то ви також повинні вказати тип цього елементу.
const input = document.querySelector('input') // тип: HTMLInputElement | null
const input = document.querySelector<HTMLInputElement>('input')
if (input) {
input.value = 'Привіт';
}
const img = document.querySelector<HTMLImageElement>('img')
if (!img) return;
img.src = 'logo.png'
const el = document.querySelector<HTMLElement>('#my-element')
const id = el?.dataset.id
const attr = el?.getAttribute('data-role')
В TypeScript існують абсоютно всі типи для всіх існуючих елементів. Перераховувати їх всі я не має сенсу, тому що їх назва залежить від самого елементу, наприклад:
- <div> - HTMLDivElement
- <form> - HTMLFormElement
- <canvas> - HTMLCanvasElement
- <a> - HTMLAnchorElement
- <img> - HTMLImageElement
- <button> - HTMLButtonElement
Всі ці назви, це по факту аналог mem типів, які були в JS ще задовго до TS, і оскільки ми зараз маємо справу з динамічними фреймворками, типізація HTML це на сама часто-викорустовуєма річ, але якщо ви будете це використовувати, або бачити в коді, то знайте, що всі ці типи можно легко знайти в енциклопедії.
Типізація евентів
Як ви знаєте в DOM, окрім самих елементів, є ще евенти, які вішаються на елементи, їх потрібно також типізувати:
const button = document.querySelector<HTMLButtonElement>('button')
button?.addEventListener('click', (event: MouseEvent) => {
console.log(event.clientX, event.clientY)
})
Як і в випадку з DOM елементами, поді є дуже багато, я покажу приклад, всю ж бібліотеку ви зможете знайти в енциклопедії.
- click, mousedown, mouseup - MouseEvent
- input, change - InputEvent
- submit - SubmitEvent
- keydown, keyup, keypress - KeyboardEvent
- focus, blur - FocusEvent
- touchstart, touchend - TouchEvent
Чесно кажучи типізовувати евенти це якась дикість, тому що тип евенту ви і так вказуєте в самому евенті. Я просто не думаю, що хтось може не зрозуміти, що addEventListener('keypress') відноситься не до клавіатури... Тем не менш, деякі компанії, хочуть типізувати все і у них є така можливість.
const form = document.querySelector<HTMLFormElement>('form')
form?.addEventListener('submit', (e: SubmitEvent) => {
e.preventDefault()
const target = e.target as HTMLFormElement
const formData = new FormData(target)
console.log(formData.get('email'))
})
Типізація браузерного API
Жесть з якою ви можете зіткнутися - це браузерне API. Проблема в тому, що воно постійно розширюється. Деякі методи мають підтримку із коробки, інші треба розширювати плагінами, інші взагалі не підтримуються, і не зрозуміло чи будуть. Проблема в тому, що дізнатися це ви можете тільки методом проб та помилок, тому що документація ТС не поспіває за оновленнями браузеру.
Хороший приклад вбудованих типів, це localStorage, він автомтично типізується в string або null:
localStorage.setItem('theme', 'dark')
const theme = localStorage.getItem('theme') // string | null
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition((pos) => {
console.log(pos.coords.latitude) // теж саме
})
}
В fetch тип ви вже вказуєте самостійно:
fetch('/api/user')
.then(res => res.json())
.then((data: { name: string; age: number }) => {
console.log(data.name)
})
В таких випадках вам допоможе тільки інтуіція та інтернет з актуальною інфою.
Під кінець ще хотів би показати кастомні події, ящо ви зіткалися з складими проектами, то я думаю ви вже знаєте що це таке, але як же їх типізувати, приблизно так:
const event = new CustomEvent('user-logged-in', {
detail: { id: 123 }
})
document.dispatchEvent(event)
document.addEventListener('user-logged-in', (e: CustomEvent<{ id: number }>) => {
console.log(e.detail.id)
})