typescript로 연습용 div를 만들어 style을 주려고 했는데...
var red = 'red' as const // 값이자 타입
var div =document.querySelector(".div")
div.style.color = red
원래 자바스크립트라면 정상적으로 작동 했을테지만...
typescript
라서 그런지...
div 값이 null 될 수있으니 타입지정 똑디 하라고 친절하게 알려준다.
div에 mousehover를 하니
div의 타입이 Element
| null
이 될수도 있다고 한다.
왜??
typescript는 javascript로 컴파일만 하지 브라우저와 node 환경에서 run 타임을 가지지 않는다.
그러므로 typescript compiler는 당연하게도 run타임을 가지기 전이므로 Element일수도 있고 null 일수 있어요 라고 말해주는 것일 뿐!
다시 돌아와서...
타입을 narrowing
을 해줘야 하는데 몇 가지 방법이 있다.
var red = 'red' as const // 값이자 타입
var div =document.querySelector(".div") as Element
// div의 타입이 Element가 된다.
var red = 'red' as const // 값이자 타입
var div =document.querySelector(".div")
div?.style.color = red
var div =document.querySelector(".div")
if(div instanceof Element) {
div.style.color = red
}
그런데 optional chaining과 narrowing의 코드를 사용해서 style
을 주려면 또다시 에러가 난다.
위와 같이 Element type에는 style이 존재하지 않는다고 ...
왜지??
HTMLElement
s inherit fromElement
which inherit fromNode
.
This means that your HTMLElement is simultaneously an instanceof all three. The fact that it is an HTMLElement means it has an interface that's contains methods only an HTMLElement would need like attachEvent.
위와 같이 HTMLElement
는 Node
에서 부터 상속받은 Element
로 부터 상속된 것이기에 전반적으로 단지 무수히 많은 태그들 전부를 각 명명 할 수 없으니 Element
하나라는 General
한 타입을 명시 한것 같다..
이 말인 즉슨 type이 Element
에는 style
이라는 속성이 없기에 조금더 narrowing
해주세요 라는 의미로 해석이 된다.
그러므로
var red = 'red' as const // 값이자 타입
// narrowing
var div = document.querySelector(".div") ;
// Element가 아닌 HTMLElement로 || HTMLDivElement로
if(div instanceof HTMLElement) {
div.style.color = red
}
// assertion
var div =document.querySelector(".div") as HTMLElement
div.style.color = red
위와 같이 narrowing
|| assertion을 할 때 조금더 세분화하여 타입을 명시해주거나 narrowing 해주자!!
위와 똑같은 방법으로 네이버 링크를 카카오 링크로 바꿔보자
// index.html
<a id='link' href='https://naver.com' >링크</a>
// typescript
let link = document.querySelector('#link');
if (link instanceof HTMLElement) {
link.href = 'https://kakao.com'
}
위 와같이 하면 되겠지 했지만 ;;
에러가 난다 .
Property 'href' does not exist on type 'HTMLElement
당황하지말고 HTMLElement타입에는 href 속성이 없다고 하니까
" 다른 타입으로 바꿔주자 " 생각하자
instanceof HTML
이라고 쳐주면 알아서 에디터가 타입 추천을 해주는데 거기서 a 태그는 anchor
와 같으니까 HTMLAnchorElement를 찾아보면 나오는데 이 타입으로 narrowing
하면 조작 완료
let link = document.querySelector("#link");
if(link instanceof HTMLAnchorElement){
link.href = 'https://kakao.com'
}
html 태그 종류별로 정확한 타입명칭이 있다.
a 태그는 HTMLAnchorElement
img 태그는 HTMLImageElement
h4 태그는 HTMLHeadingElement
.
.
...
와 같이 정확한 타입이 있으므로 type 지정을 확실히 해주고 조작/변경 하자.
그리고 Narrowing 하는 방법중
instanceof 를 쓰면 가장 정확한 타입 narrowing
을 할 듯하다.
그런데 위와 같은 방법 밖에 없을 까했는데
typescript에서
! 연산자를 사용 할 수도 있다.
의미는 : null이나 undefined가 될 수 없다라는 뜻을 품고 있다.
var div =document.querySelector(".div") !
이렇게 하면 !
를 붙이기 전에 타입은 Element | null
이었지만
Element
하나로 narrowing이 되는 것을 알 수 있다.
! 연산자의 사용처는
내가 짠 코드가 run 타임을 할 때 당연하게도 null | undefined가 안나오는 것을 알지만
complier는 run 타임 이전에 작동하는 것으로 type 추론이 명확하지 않았을 때 내가 슬쩍 넣어주는 걸로만 사용 해보자