Item 46 타입 선언과 관련된 세 가지 버전 이해하기

Key Points

타입스크립트를 사용할 때 다음 세 가지 사항을 추가로 고려해야 한다.

  • 라이브러리의 버전

  • 타입 선언(@types)의 버전

  • 타입스크립트의 버전

세 가지 버전 중 하나라도 맞지 않으면, 의존성과 상관없어 보이는 곳에서 엉뚱한 오류가 발생할 수 있다.

일반적으로 타입스크립트에서 의존성을 관리하는 방식은 다음과 같다. (Item 45)

  • 라이브러리를 dependencies로 설치한다.

  • 타입 정보는 devDependencies로 설치한다.

이렇게 하면 실제 라이브러리와 타입 정보의 버전이 별도로 관리하게 되는데, 이러한 방식은 네 가지 문제점이 있다.

  • 라이브러리를 업데이트했지만 실수로 타입 선언은 업데이트하지 않는 경우

    • 새로운 기능을 사용하려 할 때마다 타입 오류가 발생한다.

    • 일반적인 해결책은 타입 선언도 업데이트하는 것인데, 타입 선언의 버전이 준비되지 않았다면 보강(augmentation)을 사용하거나 직접 오픈 소스에 기여를 하는 방법이 있다.

  • 라이브러리보다 타입 선언의 버전이 최신인 경우

    • 타입 선언 없이 사용하다가 뒤늦게 설치하려고 할 때 발생한다.

    • 해결책은 라이브러리 버전을 올리거나 타입 선언의 버전을 내리는 것이다.

  • 프로젝트에서 사용하는 타입스크립트 버전보다 라이브러리에서 필요로 하는 타입스크립트 버전이 최신인 경우

    • @types 선언 자체에서 타입 오류가 발생한다.

    • 해결책은 프로젝트의 타입스크립트 버전을 올리거나, 라이브러리 타입 선언의 버전을 원래대로 내리거나, declare module 선언으로 라이브러리의 타입 정보를 없애 버리면 된다. 라이브러리에서 typeVersions를 통해 다른 타입 선언을 제공하는 방법도 있으나 실제로 DefinitelyTyped 라이브러리 중에서 1% 미만만 이 기능을 지원한다.

  • @types 의존성이 중복될 수 있다.

    • 예를 들어 @types/foo@types/bar에 의존하는 경우를 가정해보자. 만약 @types/bar가 현재 프로젝트와 호환되지 않는 버전의 @types/foo에 의존한다면 npm은 중첩된 폴더에 별도로 해당 버전을 설치해 문제를 해결하려고 한다.

    • 런타임에서 사용하는 모듈이라면 괜찮을 수 있지만, 전역 네임스페이스에 있는 타입 선언 모듈이라면 대부분 문제가 발생한다. 전역 네임스페이스 타입 선언이 존재하면 중복된 선언, 또는 선언이 병합될 수 없다는 오류로 나타난다. 이러한 경우 npm ls @types/foo를 실행하여 어디서 타입 선언이 발생했는지 추적할 수 있다.

    • 해결책은 보통 @types/foo 또는 @types/bar를 업데이트해서 서로 버전이 호환되도록 하는 것이다. 그러나 @types이 전이(transitive) 의존성을 가지도록 만드는 것은 종종 문제를 일으키기도 한다. 만약 타입 선언을 작성하고 공개하려 한다면 Item 51을 참고해 이런 문제를 회피하자.

번들링

일부 라이브러리, 특히 TS로 작성된 라이브러리들은 대체로 타입 선언을 포함(번들링, bundling)하게 된다.

자체적인 타입 선언은 보통 package.json의 types 필드에서 .d.ts 파일을 가리키도록 되어 있다.

번들링 방식은 부수적인 네 가지 문제점을 지니고 있다.

첫 번째, 번들된 타입 선언에 보강 기법으로 해결할 수 없는 오류가 있는 경우, 또는 공개 시점에는 잘 작동했지만 TS가 버전업되면서 오류가 발생하는 경우 문제가 된다.

  • @types을 별도로 사용한다면 라이브러리의 버전에 맞춰 선택할 수 있지만, 번들된 타입에서는 버전 선택이 불가능하다.

두 번째, 프로젝트 내의 타입 선언이 다른 라이브러리의 타입 선언에 의존한다면 문제가 된다.

  • 보통은 의존성이 devDependencies에 들어간다.(Item 45) 그러나 프로젝트를 공개해 다른 사용자가 설치하게 되면 devDependencies가 설치되지 않을 것이고, 타입 오류가 발생한다. 반면 JS 사용자 입장에서는 @types를 설치할 이유가 없으므로 dependencies에 포함하고 싶지 않을 것이다. Item 51에서 이러한 문제를 다룬다.

  • 반면, DefinitelyTyped에서 타입 선언 버전을 관리한다면 이러한 문제는 발생하지 않는다. 타입 선언이 @types에 있을 것이기 때문이다.

세 번째, 프로젝트의 과거 버전에 있는 타입 선언에 문제가 있는 경우 과거 버전으로 돌아가서 패치 업데이트를 해야 한다.

  • 번들링된 타입 선언에선 어려운 일이지만, DefinitelyTyped는 동일 라이브러리의 여러 버전의 타입 선언을 동시에 유지보수할 수 있는 메커니즘을 갖고 있다.

네 번째, 타입 선언의 패치 업데이트를 자주 하기 어렵다는 문제가 있다.

  • 라이브러리 자체보다 타입 선언에 대한 패치 업데이트가 더 많은 경우가 있는데, DefinitelyTyped는 커뮤니티에서 관리되므로 이러한 작업량을 감당할 수 있다.

권장사항

공식적인 권장사항은 라이브러리가 타입스크립트로 작성된 경우만 타입 선언을 라이브러리에 포함하는 것이다.

자바스크립트로 작성된 라이브러리를 DefinitelyTyped에 공개하여 커뮤니티에서 관리하고 유지보수하도록 맡기는 것이 좋다.

요약

  • @types 의존성과 관련된 세 가지 버전이 있다: 라이브러리 버전, @types 버전, 타입스크립트 버전

  • 라이브러리를 업데이트하는 경우, 해당 @types도 업데이트하자.

  • 타입 선언을 라이브러리에 포함하는 것과 DefinitelyTyped에 공개하는 것 사이의 장단점을 이해하자.

Last updated