export로 불러온 외부 모듈의 타입 확장하기

DefinitelyTyped 등을 통해 불러온 외부 타입 모듈을 내 필요에 맞게끔 확장해보자.

export로 불러온 외부 모듈의 타입 확장하기

Motivation

😩

DefinitelyTyped와 같은 외부 타입 모듈을 export하여 사용하다 보면, 가끔 실제 라이브러리에 적혀있는 명세와 타입 선언이 일치하지 않는 경우가 있다.

예컨대, 내가 사용하는 OpenSeadragon 라이브러리(이하 OSD)의 특정 이벤트 핸들러에는 originalEvent 라는 property가 선언되어 있음을 확인하였다.

OpenSeadragon.Viewercanvas-press 핸들러

반면, 내가 export한 @types/openseadragon 모듈에는 해당 property가 선언되어 있지 않음을 확인하였다. (해당 모듈의 타입 선언은 이 링크에서 확인할 수 있다)

이외에도 우리 팀의 코드베이스에 맞게 OSD의 타입 선언을 확장할 필요가 있었고, 검색과 삽집을 통해 찾은 확장 방법을 기록하고자 한다.

Extending Exported Type Definitions

먼저 확장된 타입을 작성하기 위한 파일을 추가해준다. StackOverflow에서 주워들은 바에 따르면, 원래 모듈과 완전히 동일한 이름을 사용하면 안된다고 하는 것 같다. 따라서 나는 openseadragon-extend.d.ts 라는 이름으로 파일을 추가하였다.

추가한 파일의 첫 줄에는 TypeScript로 하여금 우리가 확장하고자 하는 외부 타입 모듈을 참조할 수 있도록, triple-slash directive를 사용하여 reference path를 선언한다.

그 다음, 확장하고자 하는 타입의 내용을 선언해주면 된다. 예컨대, 나는 OpenSeadragon 네임스페이스에 선언된 ViewerEvent 인터페이스에 originalEvent 프로퍼티를 추가하고자 한다. 최종적으로 작성된 코드의 내용은 다음과 같다.

/// <reference path="../node_modules/types/openseadragon/index.d.ts" />

declare namespace OpenSeadragon {
  interface ViewerEvent {
    originalEvent?: Event;
  }
}

확장이 필요한 인터페이스에 이것저것 타입을 추가해주고, 마지막으로 tsconfig.json 이 설정되어 있지 않다면 includes 옵션을 적절하게 설정해줄 필요가 있다.

🎉 이제 TypeScript가 확장된 타입 선언을 잘 인식하여 빨간 줄 에러가 사라졌는지 확인하면 된다.

(부수적인) Background

내가 어떤 이유로 OpenSeadragon이라는 라이브러리를 사용하는지 궁금하실 분이 계실 것 같아(?) 짧게 작성한다.

Lunit IO from https://www.lunit.io/en/products/scope-io)

내가 소속된 팀에서 다루는 의료 데이터는 pathology slides인데, 이러한 이미지들은 일반적인 이미지와 다르게 초고해상도, 초고용량 파일이라는 특징이 있다. 따라서 웹 브라우저의 <img /> 태그를 사용할 수 없고, OSD와 같은 대용량 이미지 라이브러리를 사용하여 불러올 필요가 있다.

하지만 OSD는 JavaScript로 작성된 라이브러리이기 때문에, TypeScript의 기능을 활용하기 위해서는 외부 타입 모듈을 불러올 필요가 있다. 다행스럽게도 DefinitelyTyped에서는 OSD의 타입 모듈(@types/openseadragon)을 제공하고 있다. 이 외부 타입 모듈을 export함으로써 강력한 타입 추론 기능을 활용할 수 있다.

이 타입 모듈은 OSD 개발자들이 직접 관리하는 것은 아니고, 별개의 오픈소스 커뮤니티의 도움으로 유지보수가 이루어진다. 따라서 라이브러리 명세에 나와있는 정보와, 실제 타입 선언이 다른 경우가 발생할 수도 있다. 내 경우처럼 말이다. 😂