lib
프로퍼티를 사용하면 타겟 런타임 환경을 설명하는 번들 라이브러리 선언 파일을 지정할 수 있다.
활성화 하지 않았을 때는 기본값 즉 DOM이 설정되어 있다.
기본적으로 Typescript는 document 및 DOM 조작 항목과 DOM API의 타입을 인지하는데 만약 lib의 주석처리를 해제하면 비활성화 된다.(맨 처음tsconfig
파일을 보면 "lib" : []
이런식으로 주석처리가 되어있다)
그럼 []
이렇게 초기화 되어 있으므로 기존 typescript 파일에 작성한 document
부분에 에러가 발생한다.(document
타입을 찾지못해 any
로 설정됨)
이는 typescript 문서에서 확인할 수 있으며 DOM을 다시 추가하려면 []
배열안에 "DOM"
을 추가하자!
또한 es2021부턴 replaceAll
가 추가되었는데 이를 사용하기 위해 target
을 바꾼다면 es5에서 존재하다가 es2021에 오며 삭제된 기능들은 사용하지 못할 수 있다.
이때 lib
옵션에 DOM
과 같이 "ES2021"
와 같은 식으로 저장하면 둘 다 사용할 수 있다
하지만 꼭 수동으로 할필요는 없고 만약 이유가 있어 es5를 타겟으로 지정하고 다른 버전을 사용해야 겠다 싶으면 이런 방법이 있다 라고 알아놓자
const btn = document.getElementById("btn")
javascript로 무언가를 만들어 봤다면 자주 봤을 이 코드에서 btn은 어떤 타입일까 생각할 수 있다.
직접 console.dir
찍고 마지막 prototype
으로 봐보면 HTMLButtonElement
라고 확인된다.
그렇다면 이게 반환타입일까? 그렇지는 않다! 확인해보면
btn:HTMLElement | null
로 확인된다. 왜그럴까?
일단 HTML
요소 타입을 보면 제네릭 HTML
요소이다. 아까 console
로 확인했던 것처럼 Button
과 같은 타입이 아니다
이유는 간단히 Typescript는 알 수 없기 때문이다. 기본적으로 Typescript는 런타임이 아닌 사전에 작동하기 때문이다
Id
를 통해 추적 가능한다 하여도 그게 h1
태그에 있을지 div
태그에 있을지 모르기 때문에 getElementById
가 반환하는 게 제네릭HTML
요소이구나만 인지하는 것!
그렇기에 null
도 존재하는지 안하는지 사전에 작동하기 때문에 몰라서 만약 없다면 null
로 표기할게 하는 거와 같다
이 null
값이 이전 React를 통해 프로젝트 작업할때 매우 짜증난 적이 많았다.
분명 존재하는 값이고 있는데 이놈의 null
때문에 자꾸 ?
연산자를 넣어서 해결은 했지만 정확한 이유를 몰랐었는데 다시 공부하면서 깨닫는 부분이다.
여기서 ?
를 이용해 Javascript에게 넘기는 게 아닌 Typescript에서의 접근 방법이 있다.
non-null
단언 연산자인데 그냥 !
이다
const btn = document.getElementById("btn")!
btn.addEventListener("click", ()=>{
alert("Clicked")
})
저 const btn
끝의 !
가 절대 null
이 되지 않는다고 typescript
에 약속하는 것이다
하지만 ?
연산자보단 조금 위험할 수는 있다.
그러니 값이 확실하게 존재하고 null이 아닐때 ?
를 그만사용하고 싶다? 일때만 사용하자
타입 단언 개념은 TS에 선언하는 것으로 이 값을 다른 타입으로 취급하려 할 때 사용한다.
내가 확실한 타입 정보를 가지고 있고 TS의 정보가 부족한 상황에서 사용하면 유용하다.
약간 억지 예시를 넣는다면
let mystery:unknown = "Hello World!!!";
const numChars = mystery.length // unknown이기 때문에 length를 사용할 수 없다는 에러가 발생한다
const numChars = (mystery as string).length // 정상동작한다! 하지만 mystery의 타입을 확인하면 여전히 unknown이다
as
를 통해 타입단언을 이용하고 실제 DOM에서 쓰이는 경우가 있다.(react 프로젝트시 몇번 이용했다! target의 id 속성을 자꾸 가져오지 못하는 경우가 있어서 as
를 활용한 타입 단언으로 실행했다)
<input id="todoinput" type="text" />
이와 같은 input
태그가 있고 입력된 값을 꺼내오고 싶다.
const input = document.getElementById("todoinput")
const inputValue = input.value
보통 javascript로 가져오면 이런식으로 input값을 꺼낼 것이다. 그럼 Typescript는 어떻게 할까?
const input = document.getElementById("todoinput")!;
input.value // 접근하려면 HTML제네릭 요소엔 value가 존재하지 않는다는 에러가 생긴다
왜 에러가 생길까? 값은 HTML input요소에 존재하고 다른 HTML태그에는 존재하지 않는 경우도 많다.(image 등)
제네릭 HTML
요소는 값을 가지지 않기에 에러가 생기는 것! 이를 typescript에게 단순한 HTML요소가 아니고 HTML input이라고 알려줘야 한다.
const input = document.getElementById("todoinput")! as HTMLInputElement;
const inputValue = input.value
이후 더이상 에러가 발생하지 않는다!
as
를 대신해서 사용할 수 있는 구문이 있는데 <>
이다
const input = document.getElementById("todoinput")!;
const inputValue = (<HTMLInputElement>input).value
이렇게 작성해도 에러가 발생하지 않는다. 다만 이 구문은 일반적이지 않고 JSX에서 동작하지 않으므로 react에선 에러가 발생한다
form 태그를 이용해 addEventListener
로 submit
을 했을 때 뒤의 콜백함수의 event 타입
SubmitEvent
<- 아마 typescript가 자동으로 추적해줄 것이다.function handleSubmit(event: SubmitEvent){
event.preventDefault();
//....some code
}
이는 다른 이벤트 타입을 사용할 때도 마찬가지이다.