[TypeScript] HTML 속성 제어하기 (타입검사 및 narrowing)

keynene·2023년 8월 3일
0

TypeScript

목록 보기
4/5
post-thumbnail

요즘 난 React로만 개발하다보니 HTML을 직접적으로 제어할 기회가 많이 없었는데,
TypeScript를 공부하다보니 문득 getElementsByquerySelector로 가져온 데이터들도 타입검사가 필요할 것 같다는 생각이 들었다.

JavaScript에서 DOM 속성들 제어하는 문법들
JavaScript를 공부하며 메모 수준으로 쓴 글이지만 저 문법들이 HTML 속성을 제어하는 데 주로 쓰이고 있다😅

아무튼 이러한 문법으로 가져온 데이터의 타입을 검사하는 방법 그리고 narrowing하는 방법까지 알아보도록 하자.




간략하게, JavaScript에서 HTML속성을 제어하는 방법을 소개하자면..


  1. document.getElementsByTagName() : 특정 tag명을 가지고 있는 DOM요소 제어

  2. document.getElementsByClassName() : 특정 calss명을 가지고 있는 DOM요소 제어

  3. document.getElementById() : 특정 id명을 가지고 있는 DOM요소 제어

  4. document.guerySelector(#id명 또는 .class명) : 선택한 id명이나 class명을 가진 요소를 제어 (최상단 요소만 포함됨)

  5. document.guerySelectorAll(#id, .class) : 선택한 모든 요소를 제어




DOM 요소를 TypeScript 파일에 가져와서 제어해보자

📝 HTML파일

<p id="title">타이틀</p>
<a class="link" href="/">링크</a>
<a class="link" href="/">링크</a>
<a class="link" href="/">링크</a>
<button id="button">버튼</button>

<script src="변환된 자바스크립트파일.js"></script>

📝 TypeScript파일로 가져오기

let title = document.querySelector('#title') //id명이 title인 최상단 요소
let link = document.querySelectorAll('.link') //class명이 link인 최상단 요소
let button = document.getElementById('button') //id명이 button인 요소

우선 이렇게 하면 저장은 된다.

그렇다면
<p> 태그의 '타이틀' 'keynene입니다',
<a> 태그의 모든 링크를 '/' 'https://velog.io/@keynene' 로 변경하고,
<button> 태그는 클릭했을 때 '안녕하세요 keynene 입니다^^'라는 경고창이 뜨게 하려면 어떻게 해야할까


📝 DOM 요소 제어해보기

/* '타이틀' → 'keynene입니다' */
let title = document.querySelector('#title')
title.innerHTML = 'keynene입니다'


/* '/' → 'https://velog.io/@keynene' */
let link = document.querySelectorAll('.link')
link.forEach((l) => {
  l.href = 'https://velog.io/@keynene'
})


/* 버튼 클릭 시 '안녕하세요 keynene 입니다^^' 경고창 */
let button = document.getElementById('button')
button.addEventListener('click', function(){
  alert('안녕하세요 keynene 입니다^^')
})

console.log(title) //null
console.log(link) //null
console.log(button) //null

분명 JavaScript로 데이터 가져오는 방법까지는 확실한데, 콘솔을 찍어보면 이상하게 다 null이 출력되는 것을 확인할 수 있다.
아니 정확히는 셀렉터로 html을 찾으면 타입이 Element | null인 것을 알 수 있다.

이게 바로 TypeScript의 가장 큰 특징이고, union type으로 인해 narrowing이 필요한 이유이다.
narrowing이란 ?

이제 우리는 저 Element | null이라는 모호한 타입을 Element라고 정확히 지정해주는 narrowing이라는 작업을 하면 된다.




타입검사 및 Narrowing

📝 타입검사와 Narrowing까지 완벽하게

사실 타입검사를 하는 방법도 typeof연산자, instanceof연산자 등 방법이 많은데,
여기서는 instanceof연산자를 사용하겠다.

/* '타이틀' → 'keynene입니다' */
let title = document.querySelector('#title')
if (title instanceof HTMLElement){  //title이 HTMLElement에 포함되면 아래코드 실행
  title.innerHTML = 'keynene입니다'
}


/* '/' → 'https://velog.io/@keynene' */
let link = document.querySelectorAll('.link')
link.forEach((l) => {
  if (l instanceof HTMLAnchorElement){ //l이 HTMLAnchorElement에 포함되면 아래코드 실행
  	l.href = 'https://velog.io/@keynene'
  }
})


/* 버튼 클릭 시 '안녕하세요 keynene 입니다^^' 경고창 */
let button = document.getElementById('button')
button?.addEventListener('click', function(){
  alert('안녕하세요 keynene 입니다^^')
})

이렇게 하면 if문을 통해 narrowing되어 모든 데이터가 null이 아닌 Element타입일 때 정상적으로 실행되는 것을 확인할 수 있을 것이다.

그리고 buttonlink와 마찬가지로

if (button instanceof HTMLButtonElement){ 
  //실행할코드 
}

로 타입검사 및 변경해도 되지만, 위와 같이 es6버전의 ?기능으로도 narrowing이 가능하다.

하지만 엄격한 타입의 구분을 위해서라면 제어를 원하는 데이터의 타입을 정확히 설계/파악해두고 instanceof HTMLElement와 같은 방법으로 narrowing해주는 것이 안전하다.

(ex. ?으로 narrowing 하면 buttonnull이 아니기만하면 코드가 실행되어 버리는데, Element타입이 아닌 다른 타입이어도 코드가 실행된다는 소리니까!)




📚 TypeScript에서의 DOM 제어하기

  1. JavaScript와는 달리 TypeScript는 엘리먼트들의 타입도 정확히 설계/파악해야 한다.
  2. DOM 엘리먼트 제어 시 typeof, instanceof 등의 연산자로 타입검사를 하자.
    (?도 있긴하지만 비교적 불안전하다.)
  3. 타입검사를 했으면 narrowing해주자.
profile
keynene

0개의 댓글

관련 채용 정보