타입스크립트로 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개
- 요소 !== null
- **instanceof 연산자** -> 가장 많이 쓰게 될 것임
if(제목 instanceof Element)
- as로 사기치기
let 제목 = document.querySelector("#title") as Element;
근데 as로 타입을 사기칠거면 타입스크립트를 쓰는 의미가 없다.
- 오브젝트에 붙이는 ?. (optional chaining)
- 제목에 innerHTML이 있으면 출력해주고
- 없으면 undefined 뱉음
if(제목?.innerHTML != undefined) // narrowing 인정해줌
- 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 타입을 상속한 타입들이 더 있다.
- Element 타입 (대표적)
- HTMLAnchorElement 타입
- HTMLHeadingElement 타입
- HTMLButtonElement 타입
- ...
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'
}
}
'Front-End: Web > TypeScript' 카테고리의 다른 글
[코딩애플] ts part 1-11. interface (0) | 2022.10.22 |
---|---|
[코딩애플] ts part 1-10. class types (0) | 2022.10.22 |
[코딩애플] ts part 1-8. method types (0) | 2022.10.22 |
[코딩애플] ts part 1-7. Literal Types (0) | 2022.10.22 |
[코딩애플] ts part 1-6. Type Alias (0) | 2022.10.22 |