typescript-kr.github.io/pages/tutorials/dom-manipulation.html
사실, 배울 필요 없이 MDN보면 다 나와있다.
프론트 프레임웤, 특히 React에서 직접 DOM을 다루는 것은 잘못된 방식이지만, 그 외의 상황에선 당연히 DOM을 다룰 수 있습니다.
DOM과 Event에 대한 타입은 lib.dom.d.ts에 정의되어 있습니다. IDE 상에서 보고 싶으면 Element, HTMLElement 등을 검색하여 살펴봅시다.
솔직히, 외울 필요없이 MDN 문서를 뒤져보면, 타입에 대한 위계를 살펴볼 수 있습니다.
developer.mozilla.org/en-US/docs/Web/API
예를 들어, video태그를 사용한다고 하면, HTMLVideoElement를 타입으로 사용하고 싶을 경우
해당 타입의 위계가 HTMLMediaElement, HTMLElement, Element, Node로 이어지는 것을 확인할 수 있습니다.
그러나, 역시 자주 사용하는 것은 외워지기 마련입니다. 아래 글에서는 자주 사용하는 타입을 다뤄보았습니다.
1. 간단히 Element 타입 살펴보기, querySelector
Elment는 돔을 이루는 기본이고, 이를 extends한 것으로 이루어져 있습니다.
* 물론 Element가 형태소인 것은 아닙니다. 많은 내용들을 extends한 것을 lib.dom.d.ts에서 살펴보실 수 있습니다.
interface Element extends Node, Animatable, ChildNode, InnerHTML, NonDocumentTypeChildNode, ParentNode, Slottable
Element
> HTMLElement
> HTMLParagraphElement, HTMLSpanElement, HTMLDivElement 등등
등 구체적인 엘레먼트들 존재합니다. 당연히 HTML 태그 별 속성이 다르므로 해당 타입에 정의된 속성도 다릅니다.
<p class="dom"></p>
평소 js에서 하던대로 작성하면 Property 'innerText' does not exist on type 'Element' 에러가 발생합니다.
즉, myDom은 Element로 추론이 되었고, Element 타입에는 innerText가 없다는 겁니다.
const myDom = document.querySelector(".dom");
myDom.innerText = "someword"; // Error!
따라서, innerText를 가진 HTMLParagraphqElement 타입을 assersion 해주어야 합니다.
// 아래 같은 방식은 에러가 남. querySelector 함수 결과값 타입이 Element이기 때문
const myDom: HTMLParagraphElment = document.querySelector(".dom")
// 타입 단언으로 타입 에러 해결 가능
const myDom = document.querySelector(".dom") as HTMLParagraphElement;
createElement, querySelector, querySelectorAll 등의 메서드를 확인해보면, 어떤값을 반환하는지에 대한 정의가 되어 있습니다.
정의를 외울 필요는 없지만, 커서를 호버에서 함수가 무엇을 리턴하는지 확인하고, 필요시 타입 단언을 통해서 타입 에러를 해결할 수 있어야 합니다.
/**
* 선택자와 일치하는 노드의 자식 중 첫 번째 요소를 반환합니다.
*/
querySelector<K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K] | null;
querySelector<K extends keyof SVGElementTagNameMap>(selectors: K): SVGElementTagNameMap[K] | null;
querySelector<E extends Element = Element>(selectors: string): E | null;
/**
* 선택자와 일치하는 모든 노드 자식 요소를 반환합니다.
*/
querySelectorAll<K extends keyof HTMLElementTagNameMap>(selectors: K): NodeListOf<HTMLElementTagNameMap[K]>;
querySelectorAll<K extends keyof SVGElementTagNameMap>(selectors: K): NodeListOf<SVGElementTagNameMap[K]>;
querySelectorAll<E extends Element = Element>(selectors: string): NodeListOf<E>;
2. Event 타입의 위계 및 eventListener overload 에러 해결
Elment와 HTMLElemnt의 위계가 존재하는 것처럼, Event에도 위계가 존재합니다.
Event
> UIEvent
> MouseEvent, TouchEvent, FocusEvent, KeyboardEvent, InputEvent 등
Event 관련 작업을 하다보면, overload 에러가 자주나게 됩니다.
tsconfig.js에서 strictFunctionTypes로 설정한 경우, 이벤트 리스너에서 에러를 자주 뱉습니다.
가장 대표적인 예를 들어보면 다음과 같습니다.
myDom.addEventListener('click', handleClick); // Error!
function handleClick(event: MouseEvent) {
// ...logic
}
addEventListner를 호버해서 타입을 살펴보면 콜백 함수의 인자로 Event 를 받기를 원하고 있습니다.
아래처럼 바꿔주면 타입에 맞아 타입 에러를 회피할 수 있습니다.
function handleClick(event: Event) {
// ...logic
}
'Programming Language > 🟦 Typescript' 카테고리의 다른 글
window 객체 extends하기 (0) | 2021.04.04 |
---|---|
enum, const enum,as const의 enum화 (0) | 2021.03.15 |
Mapped Type (0) | 2021.03.01 |
@Decorator (3) : reflect-metadata (0) | 2021.01.13 |
@Decorator (2) : Decorator 예시 보며 활용 방법 익히기 (0) | 2021.01.13 |