[예전 글 다시쓰기] .d.ts 파일이란?

도깨비젤리

·

2022. 6. 26. 19:37

 

 

과거에 썼던 글 https://spookyjelly.tistory.com/39 을 다시 쓴 글입니다.

 

 

0. 들어가는 말


약 1년 전에 d.ts 파일에 관해 글을 적었는데, 지금 와서 다시 읽어보니 글의 깊이가 없고 거의 위키 글을 복붙한 수준이라 다시 한번 작성합니다. 

 

놀랍게도 저 글이 지금 제 블로그 인기 글 중 하나라는 건데, 계속 방치 해두고 있다가는 블로그의 신용을 마구 깍아 먹을 것 같습니다. 제대로 된 지식을 공유하고자 하는 목적과 블로그의 신용 회복이라는 두 마리 토끼를 잡기 위해 .d.ts 파일에 대한 지식이 어느 정도 쌓인 지금, 다시 한 번 .d.ts 파일에 대한 글을 써보려고 합니다.

 

 

 

1. d.ts 파일이 필요한 이유


.d.ts 파일은 JS 모듈을 TS에서도 사용할 수 있도록 타입만을 선언한 파일

 

아시다시피, 자바스크립트에 정적 타이핑을 끼얹은 것이 타입스크립트입니다. 이름부터 타입을 달고 있는 타입스크립트는 타입에 굉장히 예민한데요. 명확한 타입을 지정해주지 않으면, 컴파일조차 되지 않는 특징을 가지고 있습니다. (심지어 내장 타입인 any를 사용해도 any 사용하지 말라고 빨간줄을 마구마구 그어버립니다.) 

 

이러한 특징 덕에 제대로 된 타입 아래에서는 개발자로 하여금 안전한 코딩을 가능하게 하지만, 타입이 없는 패키지를 사용해야할 때 골치거리가 되기도 합니다. 특히 서드 파티 라이브러리를 사용할 때 이런 문제가 발생합니다.

 

 

d.ts 파일을 제공하지 않는 라이브러리의 예시

 

사실 요즘 시대에 타입을 제공하지 않는 라이브러리를 찾아보긴 힘들긴 하지만, 그래도 가아아아끔 이렇게 땡 JS로 짜인 라이브러리들이 존재합니다. 이런 친구들을 .ts 에서 쓰려고 하면 컴파일러가 눈에 쌍심지를 켜고 "타입 선언이 !!! 되어있지 않습니다!!! npm i @types/js-stringify 를 하던가!!! .d.ts 파일을 declare 하세요!!!!" 라고 일갈합니다. 벌써부터 스트레스 받습니다.

 

만약 이 라이브러리가 별도의 @types 패키지를 제공하는 경우는 아무런 문제가 없습니다. 그냥 npm i @types/js-stringify를 하면 끝이니까요.

 

그럼 만약 제공하지 않는 경우는 어떻게 해야하는 걸까요?? 눈물을 머금고 js 파일을 만들어서 거기서 가져다 쓰던가, 라이브러리 사용을 포기해야하는 걸까요?

 

정답은 당연히 아닙니다. 

 

개발자가 직접 타입을 .d.ts 파일에 적어넣어서 타입스크립트에서도 사용할 수 있습니다. 

 

그럼 간단한 예제를 통해서 .d.ts 파일을 선언하는 방법과, .d.ts 파일에 대해서 알아보겠습니다.

 

 

 

 

2. d.ts 파일의 사용


 

우선 빈 폴더를 하나 만드시고, 아래와 같이 셋팅해줍시다.

 

 

//package.json

{
  "name": "sandbox",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "typescript": "^4.7.4"
  },
  "dependencies": {
    "random-joke": "^1.0.5"
  }
}

 

별거 없습니다.  그냥 타입스크립트랑 random-joke 라이브러리를 설치하시면 됩니다.

 

random-joke는 fetch로 랜덤한 농담 하나를 받아오는 npm 라이브러리입니다. 거의 반 농담식으로 만들어진 패키지이고, 내용도 별거 없어서 타입 선언 연습할 용도로 적절하다 생각해 다운로드 했습니다.

 

https://www.npmjs.com/package/random-joke

 

random-joke

returns a random joke using promises.. Latest version: 1.0.5, last published: 2 years ago. Start using random-joke in your project by running `npm i random-joke`. There are no other projects in the npm registry using random-joke.

www.npmjs.com

 

1. 타입스크립트 설치하신 이후 tsc --init 명령어로 tsconfig.json을 생성하는 것을 잊지마세요.

 

 

 

 

여기까지 완료했으면 상황 설정은 끝입니다. 이제 루트에 index.ts 파일을 생성하시고, 아래와 같이 타이핑 해봅시다.

 

import { getRandomJoke } from "random-joke";

getRandomJoke().then((value: any) => console.log(value));

 

그러면 빨간 줄이 쳐질텐데, 한번 봅시다

 

 

보이시다시피,  random-joke에 대해 decalartion file이 제공되지 않았다는 건데, 이제부터 이걸 만들어봅시다.

 

그 전에 먼저, random-joke 이 놈이 어떻게 생겼는지 봅시다. node_modules/random-joke로 이동합시다.

 

 

 

 

 

진짜 별 거 없네요. getRandomJoke라는 놈만을 export 하고 있는데, Promise를 리턴하는 익명함수입니다.

 

그럼 이제 타입을 만들어주러 갑시다.

 

프로젝트의 루트에 types/index.d.ts 를 만들어줍시다.

 

//type/index.d.ts

declare module "random-joke" {
  const getRandomJoke: () => Promise<any>;
  export { getRandomJoke };
}

 

보나마나 string 리턴할것이 뻔하지만, 혹시 몰라서 일단 any로 해줬습니다.

 

저장하고 index.ts로 가봅시다. 빨간줄이 사라진것을 확인할 수 있습니다.

index.d.ts에 선언했던 타입까지 잡아주고, 자동완성까지 됩니다.

 

이렇듯, d.ts은 타입이 존재하지 않는 자바스크립트 코드에 타입을 끼얹어줌으로서 타입스크립트 파일에서도 사용할 수 있게 해주는 파일임을 확인할 수 있었습니다.

 

 

컴파일하고 실행까지 해볼까요??

 

tsc index.ts && node index.js

 

 

잘됩니다.

 

그럼 .ts 파일에 type 선언한다음 export 해서 type import 하는거와 뭐가 다른지 궁금하실텐데요.

 

사실 결과는 동일합니다.  확인해봅시다.

 

// /general.ts 
export type Joke = Promise<any>;


// /index.ts

import { getRandomJoke } from "random-joke";
import { Joke } from "./general";
getRandomJoke().then((value: string) => console.log(value));

const getJoke: Joke = getRandomJoke().then((value: string) =>
  console.log(value)
);


// 컴파일 후 실행 시 동일하게 농담이 나옵니다

 

결과는 동일하지만, index.ts에 타입을 불러오기 위한 import 문이 한 줄 더 추가 되었고, 타입을 선언한 general.ts은 ts 파일이기 때문에 컴파일러에 의해서  js로 컴파일이 됩니다. 비록 type은 컴파일 이후 삭제되긴 하지만, 그래도 불필요한 general.js 라는 파일이 생기고, 괜한 import 문만 한 줄 더 추가된건 깔끔하지 않습니다.

 

 

.ts와 달리 .d.ts 파일은 자바스크립트 코드를 타입스크립트에서 사용할 수 있도록 컴파일러에게 타입을 제공해주는, 순수하게 type definition만을 위한 파일입니다. 그렇기 때문에 이미 존재하는 자바스크립트 소스에 대한 타입만을 제공할 요량이라면, d.ts로 작성하시는것이 더 효율적입니다.