타입스크립트에서 DOM에 접근하기

TypeScript에서 DOM 요소와 이벤트 대상에 접근할 때 타입 단언과 instanceof를 사용하는 방법.

TypeScript, Frontend

보통 리액트같은 프레임워크를 통해 프론트엔드를 개발할 때는 document 객체의 querySelector, getElementById, getElementByClass 등으로 DOM에 직접 접근해서 조작하지는 않으나, 바닐라 자바스크립트나 타입스크립트로 프론트엔드를 개발하는 등 그 외의 경우에는 조작하는 경우가 있을 수 있다.

먼저 HTML DOM의 위계를 알아야 한다.
먼저 HTML DOM의 위계를 알아야 한다.

The HTML DOM API - Web APIs | MDN

const num = document.getElementById("num");
console.log(num); // <span id="num"></span>

평소 자바스크립트에서 DOM에 접근해 조작하던 방식처럼 하게 된다면, 콘솔 로그 상에서는 정상적으로 할당된 것 처럼 보인다.

const num = document.querySelector("span");
num.innerText = "0"; // Error!
num.addEventListener("click", callback); // Error!

하지만, addEventListener를 통해 이벤트를 위임하거나, innerText를 통해 값을 넣어주는 경우 “Object is possibly ‘null'.” 메세지의 에러가 발생한다.

document.querySelector와 같은 DOM 선택자 메서드는 HTMLElement 혹은 null을 반환하는데, HTMLElement가 아닌 다른 타입으로 추론되었고, 그에 따라서 타입스크립트는 해당 변수 혹은 상수가 addEventListener나 innerText 같은 메서드나 프로퍼티를 갖고있지 않다고 판단했기 때문이다.

이런 경우 타입 단언(Type Assertion)을 통해 에러를 해결할 수 있다. 타입 단언이란, 컴파일러에게 해당 타입에 대해 더 잘 알고 있다고 말해주는 것인데,

const num = document.querySelector("span") as HTMLSpanElement;
num.innerText = "0";
num.addEventListener("click", callback);

이런 식으로 타입 단언을 통해 타입 에러를 해결해준다면, 정상적으로 메서드와 프로퍼티에 접근할 수 있게 된다.

또, input이나 button, form 같은 태그에서 id나 class, value에 접근할때, 자바스크립트에서는 event.target.value에 접근해서 조작하게 되는데,

const onClick = (e: Event) => {
  
  const foo = e.target;
  
  console.log(foo.value); // 'EventTarget' 형식에 'value' 속성이 없습니다.
}

타입스크립트에서는 인자로 이벤트 타입을 잘 설정해줬음에도 이런 에러를 뿜어내는 경우가 있다.

그 이유는 타입스크립트에서는 브라우저마다 속성이 다르기때문에 공통적으로 속성을 갖게 만들어두기 어려워서, 아직 어떤 엘리먼트인지 모른다고 판단하기 때문이다.

const onClick = (e: Event) => {
  
  const foo = e.target as HTMLButtonElement;
 
  console.log(foo.value); // 타입 단언을 통한 에러 해결
}

이 경우에도 타입 단언을 통해 해결할 수 있으며,

const onClick = (e: Event) => {
  
  const foo = e.target;
  if (foo instanceof Element) { // Element || HTMLButtonElement
    console.log(item.id); // instanceof 연산자를 통한 에러 해결
  }
}

instanceof 연산자를 통해 타입스크립트에게 Element.prototype이 foo객체의 프로토타입 체인에 있는지 검사하라고 말해주어 해결할 수도 있다.

instanceof - JavaScript | MDN

TypeScript 한글 문서


원문: Medium