any
타입스크립트를 사용하는 가장 큰 이유중 하나는 타입을 명시적으로 지정하여 오류를 미리 방지하는 것이라고 할 수 있다. 그렇기 때문에 기존 자바스크립트 프로젝트에 타입스크립트를 적용하고자 할 때 아직 어떤 타입을 할당해야 할지 못하는 경우 어떤 타입도 할당 가능하도록 any를 설정할 수 있다.
// tsconfig.json
{
"compilerOptions": {
... 생략
"noImplicitAny": true
},
}
타입스크립트 설정파일에서 "noImplicitAny" 옵션을 true로 주면 any 타입을 암시적으로 표현한 후분에 대해 에러를 표시해 준다. 그러므로 개발자는 명시적으로 any를 지정해 주거나 알맞는 타입을 지정해 주어야 한다.
DOM 관련 타입 오류
기존 자바스크립트에서는 에러가 나지 않는 부분이지만 타입스크립트에서는 위와같이 에러가 발생한다. 먼저 에러 구문을 보면 Element 형식에 innerText 속성이 없다고 하는데 그럼 Element는 무엇일까?
lib.dom.d.ts를 보면 Element는 아래와같이 정의되어 있다. Node, Animatable, ChildNode 등등 여러가지 요소들을 상속받는다.
interface Element extends Node,
Animatable,
ChildNode,
InnerHTML,
NonDocumentTypeChildNode,
ParentNode,
Slottable
Element 보다 하위 개념인 HTMLElement 는 Element를 포함한 여러 요소들을 상속 받고 있다.
interface HTMLElement extends Element,
DocumentAndElementEventHandlers,
ElementCSSInlineStyle,
ElementCSSInlineStyle,
ElementContentEditable,
GlobalEventHandlers,
HTMLOrSVGElement
function $(selector: string) {
return document.querySelector(selector);
}
const test = $('.test');
test.innerText = 'test';
.test 선택자로 가져온 요소가 <p> 태그를 사용한 요소라면 HTMLElement 하위에 있는 HTMLParagraphElement 라고 추론을 할 수 있을 것이다. 그래서 test에 해당 타입을 지정해 줬더니
이번엔 이런 에러가 발생하였다. 이 에러가 발생하는 이유는 유틸함수인 '$' 함수의 반환값은 아직 Element 이므로 test 변수는 Element 타입이라고 추론할 것이다. 하지만 HTMLParagraphElement 는 Element, HTMLElement 를 상속받아 확장한 자식 요소이기 때문에 위와 같은 에러가 발생하는 것이다.
그럼 이 부분은 어떻게 해결해야 할까?
바로 타입 단언을 의미하는 'as'를 사용하면 된다.
function $(selector: string) {
return document.querySelector(selector);
}
const test = $('.test') as HTMLParagraphElement;
test.innerText = 'test';
DOM util 함수 리펙토링
// DOM selector
function $(selector: string) {
return document.querySelector(selector);
}
const foo = $('.foo') as HTMLParagraphElement;
const bar = $('.bar') as HTMLParagraphElement;
const baz = $('.baz') as HTMLParagraphElement;
이런식으로 DOM selector 유틸 함수가 존재할 때 매번 as 키워드를 사용하여 타입을 지정해 줘야 했다.
하지만 아래와 같이 유틸 함수에 제네릭을 사용하여 HTMLElement 타입만 받을 수 있게 지정하고 사용하면 매번 as 키워드를 사용하여 지정하지 않아도 된다.
function $<T extends HTMLElement = HTMLDivElement>(selector: string) {
return document.querySelector(selector) as T;
}
const foo = $<HTMLParagraphElement>('.foo');
const bar = $<HTMLParagraphElement>('.bar');
const baz = $<HTMLParagraphElement>('.baz');
const qux = $('.qux');
그리고 제네릭을 정의하면서 기본값을 지정해 주면, qux 처럼 제네릭을 설정해주지않고 사용할 경우 기본값의 타입을 갖게 된다.
'TypeScript' 카테고리의 다른 글
TypeScript 외부 라이브러리 모듈화 (0) | 2021.06.10 |
---|---|
Typescript 설정 (0) | 2021.06.08 |
댓글