TypeScript에서 DOM 요소를 선택하는 방법: 안전하고 효율적인 접근법
DOM (Document Object Model)은 웹 페이지의 구조와 내용을 정의하는 중요한 개념이다.
HTML 문서의 html, body, div와 같은 요소들은 자바스크립트를 통해 동적으로 조작할 수 있다. 간단히 말해, 문서 객체는 자바스크립트로 수정 가능한 웹 페이지의 구성 요소들이다.
현대 웹 개발에서는 DOM을 직접적으로 다루기보다, React, Vue와 같은 프레임워크를 활용하여 DOM을 간접적으로 다루는 것이 일반적이다.
이러한 프레임워크들은 복잡한 UI를 효율적으로 관리하는 데 도움을 주지만, TypeScript의 타입 안전성이나 타입 연습을 위해 직접적인 DOM 접근도 여전히 중요한 학습 대상이라고 생각한다.
이번 글에서는 TypeScript에서 DOM 요소를 안전하게 선택하고 조작하는 여러 가지 방법을 살펴볼 예정이다.
각 방법에 대해 JavaScript 코드 예제도 함께 제시하여 이해를 돕고자 한다.
TypeScript의 타입 시스템을 활용해 코드의 안정성과 가독성을 높이는 방법을 익히는 데 이 글이 도움이 되었으면 좋겠다.!
📕목차
- 기본 선택 방법 (타입 단언 사용)
- 타입 가드를 사용한 방법
- 널 체크와 타입 가드 조합
- 제네릭을 활용한 유틸리티 함수
- 객체를 사용한 요소 선택 및 관리
- 커스텀 타입 가드 함수 사용
- NodeListOf와 HTMLCollectionOf 사용
- 타입 가드와 함께 document.createElement 사용
1. 기본 선택 방법 (타입 단언 사용)
TypeScript
const button = document.getElementById('myButton') as HTMLButtonElement;
const input = document.querySelector('.myInput') as HTMLInputElement;
button.addEventListener('click', () => { console.log('Button clicked!'); });
input.value = 'Hello World';
JavaScript
const button = document.getElementById('myButton');
const input = document.querySelector('.myInput');
button.addEventListener('click', () => { console.log('Button clicked!'); });
input.value = 'Hello World';
TypeScript에서 as 연산자를 사용하여 DOM 요소의 타입을 명시적으로 지정할 수 있다.
이 방법은 요소가 존재하는 것이 확실할 때 유용하지만, 요소가 null일 가능성이 있을 때는 타입 안전성을 보장하지 않는다.
따라서 요소가 null이 아님을 보장하기 위해서는 다음에 소개할 타입 가드를 활용할 수 있다.
2. 타입 가드를 사용한 방법
TypeScript
const element = document.getElementById('myElement');
if (element instanceof HTMLInputElement) { element.value = 'Hello'; }
JavaScript
const element = document.getElementById('myElement');
if (element instanceof HTMLInputElement) { element.value = 'Hello'; }
'instanceof 연산자'를 사용하여 요소의 타입을 확인한다.
이는 TypeScript에서 타입을 좁히는 방법으로, 요소의 실제 타입을 확인하여 안전하게 속성에 접근할 수 있다.
3. 널 체크와 타입 가드 조합
TypeScript
const div = document.querySelector('.myDiv');
if (div && div instanceof HTMLDivElement) { div.innerHTML = 'Content'; }
JavaScript
const div = document.querySelector('.myDiv');
if (div instanceof HTMLDivElement) { div.innerHTML = 'Content'; }
null 체크와 타입 가드를 조합하여 요소가 존재하며 올바른 타입인지 확인한다.
이 방법은 요소가 존재하지 않을 경우(null or undefined)의 오류를 방지하고 타입 안전성을 보장할 수 있다.
4. 제네릭을 활용한 유틸리티 함수
TypeScript
function getElement<T extends HTMLElement>(selector: string): T | null {
return document.querySelector(selector);
}
const img = getElement<HTMLImageElement>('#myImage');
if (img) {
img.src = 'newImage.jpg';
}
JavaScript
function getElement(selector) {
return document.querySelector(selector);
}
const img = getElement('#myImage');
if (img) {
img.src = 'newImage.jpg';
}
제네릭을 사용하여 다양한 타입의 요소를 반환할 수 있는 유틸리티 함수를 정의한다.
TypeScript에서는 반환값의 타입을 지정할 수 있어 더욱 타입 안전한 코드를 작성할 수 있다.
5. 객체를 사용한 요소 선택 및 관리
TypeScript
const elements = {
button: document.getElementById('myButton') as HTMLButtonElement | null,
input: document.querySelector('.myInput') as HTMLInputElement | null,
form: document.forms.namedItem('myForm') as HTMLFormElement | null,
};
if (elements.button) {
elements.button.onclick = () => console.log('Clicked!');
}
JavaScript
const elements = {
button: document.getElementById('myButton'),
input: document.querySelector('.myInput'),
form: document.forms.namedItem('myForm'),
};
if (elements.button) {
elements.button.onclick = () => console.log('Clicked!');
}
DOM 요소를 객체로 관리하여 코드를 조직적으로 유지한다.
TypeScript에서는 요소가 null일 수 있으므로 이를 고려하여 타입을 명시적으로 지정해야한다.
6. 커스텀 타입 가드 함수 사용
TypeScript
function isHTMLInputElement(element: Element): element is HTMLInputElement {
return element instanceof HTMLInputElement;
}
const element = document.querySelector('.someElement');
if (element && isHTMLInputElement(element)) {
element.value = 'New value';
}
JavaScript
function isHTMLInputElement(element) {
return element instanceof HTMLInputElement;
}
const element = document.querySelector('.someElement');
if (element && isHTMLInputElement(element)) {
element.value = 'New value';
}
커스텀 타입 가드를 사용하여 특정 타입의 요소를 확인한다. 이를 통해 복잡한 조건문 없이 타입을 정확히 좁힐 수 있다.
7. NodeListOf와 HTMLCollectionOf 사용
TypeScript
const buttons = document.querySelectorAll('.button') as NodeListOf<HTMLButtonElement>;
const divs = document.getElementsByClassName('myDiv') as HTMLCollectionOf<HTMLDivElement>;
buttons.forEach(button => button.addEventListener('click', () => console.log('Button clicked')));
JavaScript
const buttons = document.querySelectorAll('.button');
const divs = document.getElementsByClassName('myDiv');
buttons.forEach(button => button.addEventListener('click', () => console.log('Button clicked')));
NodeListOf와 HTMLCollectionOf를 사용하여 컬렉션 타입의 요소를 다룬다.
TypeScript에서는 각 요소의 타입을 명시적으로 지정하여 타입 안전성을 유지할 수 있다.
8. 타입 가드와 함께 document.createElement 사용
TypeScript
function createAndAppend<K extends keyof HTMLElementTagNameMap>(tag: K, parent: HTMLElement) {
const element = document.createElement(tag);
parent.appendChild(element);
return element;
}
const div = document.getElementById('container');
if (div instanceof HTMLDivElement) {
const newButton = createAndAppend('button', div);
newButton.textContent = 'Click me';
}
JavaScript
function createAndAppend(tag, parent) {
const element = document.createElement(tag);
parent.appendChild(element);
return element;
}
const div = document.getElementById('container');
if (div instanceof HTMLDivElement) {
const newButton = createAndAppend('button', div);
newButton.textContent = 'Click me';
}
document.createElement를 사용할 때 타입 가드를 통해 부모 요소의 타입을 확인하고, 제네릭을 사용하여 다양한 태그의 요소를 동적으로 생성한다.
마무리
이 글에서는 TypeScript에서 DOM 요소를 안전하고 효율적으로 다루기 위한 다양한 방법을 살펴보았다.
JavaScript와 TypeScript 모두에서 DOM 요소를 선택하고 처리하는 데 있어, 각 접근법의 장단점과 실용성을 이해하는 것은 매우 중요하다.
TypeScript의 강력한 타입 시스템을 활용하면 코드의 안정성을 크게 향상시킬 수 있다. 기본적인 타입 단언부터 시작하여, 타입 가드와 제네릭, 그리고 커스텀 타입 가드까지 다양한 방법을 통해 우리들의 코드가 더 오류가 적고 유지보수하기 쉬워질 것이다.
글 작성을 준비하고, 작성하면서, 효율적인 코드 작성과 안정적인 애플리케이션 개발을 위해 TypeScript의 타입 시스템을 적극 활용해야함을 느꼈다.
'Typescript' 카테고리의 다른 글
JavaScript에서 TypeScript로: 3가지 방법으로 타입스크립트 도입하기 (1) | 2024.09.02 |
---|---|
TypeScript 환경 설정 (5) | 2024.08.31 |