본문 바로가기

Front-End: Web/TypeScript

[코딩애플] ts part 1-9. TypeScript DOM Manupulation

반응형

타입스크립트로 HTML 변경과 조작할 때 주의점

당연히 TypeScript로 HTML 조작 가능. 근데 좀 다르다.

// js
document.getElementById();

index.html 파일을 생성하자.

<h4 id="title">안녕하세요</h4>
<a href="naver.com">링크</a>
<button id="button">버튼</button>

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

그리고 tsconfig.json에 코드를 추가해서 strict mode를 켜주자.

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strictNullChecks": true ⬅️
  }
}
  • Null type이 들어올 때 엄격하게 체크해달라고 설정하는 것임

<h4>안의 글자를 바꿔보자

// js의 경우
let 제목 = document.querySelector("#title");
제목.innerHTML = "반가워요";

근데 '제목'이 Object is possibly 'null'이라고 **에러**가 떠서 안된다. 왜냐하면 **타입이 Element | null 이기 때문**이다. 그럼 **타입을 하나로 narrowing하자.**

이게 왜 union type이냐면, id가 없는 요소에 접근하면 요소를 못 찾아서 null이 되기 때문이다.

// ts의 경우
let 제목 = document.querySelector("#title");
if(제목 != null){
    제목.innerHTML = '반가워요';
}

HTML 조작 시 narrowing 하는 방법 5개

  1. 요소 !== null
  2. **instanceof 연산자** -> 가장 많이 쓰게 될 것임
if(제목 instanceof Element)
  1. as로 사기치기
let 제목 = document.querySelector("#title") as Element;

근데 as로 타입을 사기칠거면 타입스크립트를 쓰는 의미가 없다.

  1. 오브젝트에 붙이는 ?. (optional chaining)
    • 제목에 innerHTML이 있으면 출력해주고
    • 없으면 undefined 뱉음
if(제목?.innerHTML != undefined) // narrowing 인정해줌
  1. tsconfig.json에서 귀찮은 strict 모드를 끔

그냥 자바스크립트에서도 이렇게 코드짜면 안전하고 좋다.

<a>태그의 href 속성내용을 바꿔보자

🕹️index.html

<h4 id="title">안녕하세요</h4>
<a href="naver.com" class="link">링크</a>
<button id="button">버튼</button>

<script src="index.js"></script>

🕹️index.ts

let 링크 = document.querySelector(".link");
링크.href = "https://kakao.com";

근데 에러가 뜬다. union type이라서다. 그래서 narrowing해줘야 한다.

let 링크 = document.querySelector(".link");
if (링크 instanceof Element) {
  링크.href = "https://kakao.com";
}

근데 그래도 .href 부분에서 에러가 난다(Property 'href' does not exist on type 'Element').

왜냐하면 a 태그의 경우에는 Element가 맞는지 검사하는게 아니라, 정확하게 **HTMLAnchorElement**라고 적어서 narrowing해줘야 한다.

let 링크 = document.querySelector(".link");
if (링크 instanceof HTMLAnchorElement) {
  링크.href = "https://kakao.com";
}

그래야만 html 속성을 가져다 쓸 수 있다! 이제 에러가 안 뜬다.

왜 그럴까? 원리가 뭐냐면, 타입스크립트가 제공하는 HTML 관련 기본 타입들이 있다.

대표적으로 Element 타입이다. 그리고 이 Element 타입을 상속한 타입들이 더 있다.

  1. Element 타입 (대표적)
  2. HTMLAnchorElement 타입
  3. HTMLHeadingElement 타입
  4. HTMLButtonElement 타입
  5. ...

Element 타입 안에는 정의가 별로 안되어 있다. 그냥 광범위하게 Element를 표현하기 위해 만들어진 것 뿐이다.

근데 HTMLAnchorElement와 같이 상속되어 만들어진 타입의 경우에는, href, style, class 이런거 쓸 수 있어요~ 하고 속성들이 상세히 정의되어 있다. 그래서 이런 타입들을 작성해서 narrowing을 해줘야 한다.

<button> 태그면 HTMLButtonElement를, <h1> 태그면 HTMLHeadingElement ... 등 태그마다 정해져있다. 그걸 사용하면 된다.

타입스크립트에서 eventListener 부착하는 법

let 버튼 = document.querySelector("#button");
버튼?.addEventListener("click", function () {
  
});

이런 식으로 작성하게 될건데, 이것도 narrowing이 필요할거다. 하지만 ?.을 사용해서 narrowing도 인정해준다.

버튼에 addEventListener 가능하면 해주시고 아니면 undefined 내뱉어주세요 라고 하는 거기 때문이다.

숙제

1. 버튼을 누르면 이미지를 바꿔봅시다.

<img id="image" src="test.jpg">

html 안에 test.jpg를 보여주고 있는 이미지 태그가 있다고 칩시다.

이미지를 new.jpg 라는 이미지로 바꾸고 싶으면 자바스크립트 코드를 어떻게 짜야할까요?

성공여부는 크롬 개발자도구 켜면 src 속성이 잘 바뀌었는지 확인가능하겠죠?

➡️

let img = document.querySelector("#image");
if (img instanceof HTMLImageElement) {
  img.src = "new.jpg";
}

2. 바꾸고 싶은 html 요소가 많습니다.

<a class="naver" href="naver.com">링크</a>
<a class="naver" href="naver.com">링크</a>
<a class="naver" href="naver.com">링크</a> 

3개의 링크가 있는데 이 요소들의 href 속성을 전부 https://kakao.com으로 바꾸고 싶은 겁니다.

자바스크립트 코드를 어떻게 짜야할까요?

➡️

let anchors = document.getElementsByClassName("naver");

if (Array.isArray(anchors)) {
  anchors.forEach((a) => {
    if (a instanceof HTMLAnchorElement) {
      a.href = "https://kakao.com";
    }
  });
}

코딩애플 풀이

let 링크 = document.querySelectorAll('.naver');

링크.forEach((a)=>{
  if (a instanceof HTMLAnchorElement){
    a.href = 'https://kakao.com'
  }
})

혹은

let 링크 = document.querySelectorAll('.naver');

for (let i = 0; i < 3; i++){
  let a = 링크[i];
  if (a instanceof HTMLAnchorElement){
    a.href = 'https://kakao.com'
  }
}
반응형