TypeScript와 DOM

원도훈·2024년 12월 9일
1

안녕하세요, TypeScript를 활용하여 DOM(Document Object Model)을 효율적으로 다루는 방법에 대해 알아보겠습니다. TypeScript는 DOM 조작 시 코드의 안전성과 가독성을 높여주는 강력한 타입 시스템을 제공합니다. 이번 글에서는 TypeScript로 DOM을 조작하는 기본 방법부터 주의할 점, 그리고 실무에서 활용할 수 있는 패턴까지 다뤄보겠습니다.


DOM이란?

DOM(Document Object Model)은 HTML, XML 문서의 구조화된 표현으로, JavaScript를 통해 문서의 콘텐츠, 구조, 스타일을 동적으로 변경할 수 있는 API입니다. DOM은 트리 구조로 표현되며, 각 요소는 노드(Node)로 구성됩니다.

TypeScript는 DOM API를 포함한 타입 선언 파일을 제공하기 때문에, DOM 조작 시 강력한 타입 체크와 코드 자동 완성을 지원합니다.


TypeScript로 DOM 접근하기

기본 DOM 접근

DOM 요소를 접근하려면 TypeScript의 document 객체를 사용할 수 있습니다. 대표적으로 getElementById, querySelector 등을 활용합니다.

const heading = document.getElementById('heading');
console.log(heading?.textContent); // 요소의 텍스트 출력

타입 단언 (Type Assertion)

TypeScript는 document.getElementById의 반환 타입을 HTMLElement | null로 추론합니다. 요소가 존재하지 않을 수 있기 때문입니다. 따라서 타입 단언을 통해 더 구체적인 타입을 명시해야 합니다.

const heading = document.getElementById('heading') as HTMLHeadingElement;
console.log(heading.textContent);

querySelector와 제네릭

querySelector는 CSS 선택자를 사용해 요소를 찾을 수 있는 강력한 메서드입니다. TypeScript에서는 제네릭을 사용해 반환 타입을 지정할 수 있습니다.

const button = document.querySelector<HTMLButtonElement>('#submit-button');
button?.addEventListener('click', () => {
  console.log('버튼 클릭!');
});

위 코드에서 HTMLButtonElement 타입을 명시함으로써 버튼 요소의 고유 메서드와 속성에 접근할 수 있습니다.


DOM 요소 조작하기

속성 조작

TypeScript를 사용하면 DOM 요소의 속성을 안전하게 조작할 수 있습니다.

const input = document.querySelector<HTMLInputElement>('#user-input');
if (input) {
  input.value = 'Hello, TypeScript!';
}

위 코드에서 input 요소의 value 속성은 HTMLInputElement에 정의되어 있어 타입 체크가 가능합니다.

클래스 조작

classList를 사용하면 요소의 클래스를 쉽게 추가하거나 제거할 수 있습니다.

const box = document.querySelector<HTMLDivElement>('.box');
box?.classList.add('highlight');
box?.classList.remove('hidden');

스타일 조작

style 객체를 사용해 인라인 스타일을 변경할 수 있습니다.

const box = document.querySelector<HTMLDivElement>('.box');
if (box) {
  box.style.backgroundColor = 'blue';
  box.style.color = 'white';
}

이벤트 핸들링

이벤트 리스너 추가

TypeScript로 DOM 이벤트를 처리할 때, 이벤트 객체의 타입을 명시적으로 선언할 수 있습니다.

const button = document.querySelector<HTMLButtonElement>('#submit-button');
button?.addEventListener('click', (event: MouseEvent) => {
  console.log('클릭 이벤트 발생!', event);
});

커스텀 이벤트

TypeScript를 사용하면 커스텀 이벤트도 안전하게 처리할 수 있습니다.

const customEvent = new CustomEvent('myEvent', { detail: { message: 'Hello, Custom Event!' } });
document.dispatchEvent(customEvent);

document.addEventListener('myEvent', (event: Event) => {
  const custom = event as CustomEvent;
  console.log(custom.detail.message);
});

TypeScript로 반복 작업 단순화하기

DOM 조작을 반복적으로 수행할 경우, 유틸리티 함수를 사용하면 코드의 가독성과 재사용성을 높일 수 있습니다.

예제: DOM 요소 생성 함수

function createElement<K extends keyof HTMLElementTagNameMap>(tagName: K, options?: Partial<HTMLElementTagNameMap[K]>): HTMLElementTagNameMap[K] {
  const element = document.createElement(tagName);
  if (options) {
    Object.assign(element, options);
  }
  return element;
}

const newDiv = createElement('div', { id: 'my-div', className: 'container' });
document.body.appendChild(newDiv);

위 함수는 태그 이름과 속성을 받아 DOM 요소를 생성하고 반환합니다. 제네릭을 사용하여 태그 이름에 따라 적절한 타입을 반환하도록 설계되었습니다.


주의사항

Null 체크

TypeScript는 DOM 요소가 존재하지 않을 가능성을 항상 염두에 둡니다. 따라서 요소를 조작하기 전에 null 체크가 필요합니다.

const heading = document.getElementById('heading');
if (heading) {
  heading.textContent = '안녕하세요!';
}

런타임 오류

타입 단언(as)은 컴파일러에게 타입 정보를 제공하지만, 실제 DOM 구조와 일치하지 않을 경우 런타임 오류가 발생할 수 있습니다. 가능하면 안전한 타입 가드를 사용하는 것이 좋습니다.

const heading = document.getElementById('heading');
if (heading instanceof HTMLHeadingElement) {
  heading.textContent = '안녕하세요!';
}

결론

TypeScript는 DOM 조작 시 타입 안전성을 제공하여 런타임 오류를 줄이고 코드 가독성을 높여줍니다.

  • 타입 단언제네릭을 활용하여 DOM 요소에 정확한 타입을 지정할 수 있습니다.
  • 이벤트 핸들링 시 이벤트 객체의 타입을 명시적으로 선언하여 예측 가능한 코드를 작성할 수 있습니다.
  • 유틸리티 함수를 활용해 DOM 조작을 단순화하고 재사용성을 높일 수 있습니다.

TypeScript를 활용하여 더욱 견고하고 유지보수하기 쉬운 웹 애플리케이션을 만들어 보세요! 감사합니다. 🙌


참고 자료

profile
개발

0개의 댓글