Javascript 라이브러리에 타이핑하기

들어가기 전

개인적으로 나는 타입스크립트를 아주 좋아한다. 좋아하는 데는 여러가지 이유가 있겠지만 가장 큰 이유는 아무래도 타입을 통해 버그를 쉽게 잡을 수 있다 라는 점 때문이었다. 타입스크립트를 이용하면 얻는 이점에 대해서는 해당 포스팅에서 따로 다루진 않는다. 이 글을 읽는 분이라면 대부분 이미 타입스크립트를 사용하며 얻는 이점에 대해 공감을 하여 타입스크립트를 도입하여 사용하고 있다고 생각한다.

하지만 그런 나조차도 가끔은 회의감이 들때가 있으니 그것은 바로 라이브러리에 대한 인터페이스이다.

생각지도 못한 정체

물론 과거에 비해 요즘은 많은 라이브러리에 d.ts 파일이 존재하기도 하지만, 아직은 제로 None d.ts 시대는 아닌 것 같다.

d.ts 파일은 말 그대로 구현되어져 있는 모듈에 대한 타입 선언 파일이다. 그러므로 모듈 구현과 타입 선언은 명백하게 분리해서 생각해야 한다. 모듈 구현 코드는 런타임에서 실제 돌아가는 동작부 코드이며, 타입 선언의 경우에는 컴파일되는 과정에서의 타입 검증을 위해 사용된다.

이러한 경우에 직면할 때는 자바스크립트 라이브러리에 대해서 직접 인터페이스를 선언해줘야 한다. 물론 가끔은 다음과 같이 any 키워드를 이용하여 사용하는 경우도 있을 것이다. 귀찮음을 대변하는 타이핑이 아니라는 변명은 하지 않겠다

1
2
3
declare var $: any;

export default $;

물론 jQuery 역시 @types가 존재하기는 하지만, 과거의 최신 버전의 jQuery가 아닌 경우는 미묘하게 타입이 일치하지 않는다. 한 예로 T사에 재직 중일 당시 리뉴얼 프로젝트에서 새로 개발되는 페이지의 경우 ReactJS + Typescript 조합을 이용하여 개발하였지만, 기존의 코드와의 의존성을 끊을 수가 없었다. 하지만 기존의 코드는 1.x.x대의 jQuery를 사용하고 있었는데, 이러한 코드에 대한 타입이 없기도 했으며 부분적인 코어 모듈에서만 사용하는 라이브러리이기 때문에 any 키워드로 뭉트그려도 타입 검증이 이뤄지지 않아도 상관이 없었다.

저기 미안한데 귀찮아 짤

사실 써드 파티 라이브러리의 경우, 대부분 자체적으로 단위 테스트가 붙어 있을 정도로 어느 정도 검증된 코드들인 경우가 많다. 물론 버그가 아예 없는 경우는 없지만, 어느 정도의 궤도에 올라온 라이브러리인 경우 이미 이슈로 등록되어있던가 혹은 스택 오버플로우에 해결 방법이 거의 대부분 나와있다. 그래서 시간이 부족하거나 정말 타이핑하기가 귀찮을 경우는 any 키워드로 때려넣은 적도 있다.

자아 성찰 짤

하지만 문제는 어플리케이션 내에 강력한 영향을 미치는 라이브러리이다. 일단 본격적으로 타이핑을 해보기 전에 선행 작업이 필요하다. tsconfig.json 파일에 다음과 같이 typeRoots에 타입 선언해줄 디렉토리를 추가한다.

1
2
3
4
5
6
7
8
9
10
11
{
"compilerOptions": {
// ...
"typeRoots": [
"./node_modules/@types/",
"./@types" // 타입 선언해줄 디렉토리를 추가해준다.
],
// ...
},
// ...
}

본격적으로 타이핑 해보기

앞서와 같이 @types 디렉토리를 생성했다면 다음으로 타입을 선언해줄 d.ts 파일을 생성한다. 그 다음으로 사용하려는 라이브러리에 대하여 declare module 키워드를 이용하여 선언한다. 본 포스팅에서의 예제는 현재 사이드로 개발 중인 에디터 플랫폼에서 사용하는 써드 파티 라이브러리 중 하나인 editorjs의 의존성을 가진 라이브러리를 이용하여 작성하였다.

1
declare module '@editorjs/header';

일단 이렇게만 작성해도 거의 대부분이 끝났다. 위와 같이 선언만 해준다면 애플리케이션 내에서 문제 없이 사용할 수 있다. 하지만 이렇게 선언된 써드 파티 라이브러리의 타입은 any 타입을 가지게 된다. 만약 써드 파티 라이브러리의 타입 선언에 대해 더이상의 시간을 투자하고 싶지 않다거나 시간 관계상 현재 타이핑 하는 것이 현실적으로 불가능하다면 위와 같이 선언해도 문제는 없을 것이다.

하지만 개인적으로는 이러한 방식은 타이핑에 대한 문제를 해결하기 보단 그냥 회피하는 방법이라고 생각이 들었다.

1
2
3
4
5
6
7
8
9
declare module '@editorjs/header' {
import { BlockToolConstructable } from "@editorjs/editorjs";
interface HeaderConstructor extends BlockToolConstructable {
// 이후 추가되는 인터페이스에 대해서는 해당 영역에 작성한다.
}

const k: HeaderConstructor;
export = k;
}

다행히도 내가 사용하는 editorjs 라이브러리 안에는 각각의 tools에 해당하는 constrructor에 대한 인터페이스가 존재하였기 때문에 그 안에서 상속받는 형태로 작성하였다. 이후부터 editorjs에 추가되는 플러그인에 대해서는 각각의 타입 선언 파일 내에서 선언하면 되지 않을까 한다.

마치며

대략적으로 자바스크립트 라이브러리에 타이핑을 하는 방법을 살펴보았다. 과거 불과 1년여 전만 해도 이러한 써드 파티 라이브러리에 대해 타이핑하는 것 때문에 타입스크립트 도입을 꺼려하는 개발자들이 많았다. 하지만 더 이상 타입스크립트의 도입에 반대하는 의견 중 가장 큰 원인이 써드 파티 라이브러리에 대한 타입이 원인이 되기는 힘들다는 생각이 든다. 물론 이것조차도 누군가에겐 부정적인 의견을 가질 수 있겠지만…


출처

현재 이커머스회사에서 frontend 개발자로 업무를 진행하고 있는 Martin 입니다. 글을 읽으시고 궁금한 점은 댓글 혹은 메일(hoons0131@gmail.com)로 연락해주시면 빠른 회신 드리도록 하겠습니다. 이 외에도 네트워킹에 대해서는 언제나 환영입니다.:Martin(https://github.com/martinYounghoonKim
흔한 주니어 개발자의 VueJS 책 집필기
Typescript와 NodeJS를 이용한 간단한 목킹 서버 띄우기 01