- Published on
타입 선언과 @types - Item 45 ~ 47
타입 선언과 @types - Item 45 ~ 47
Item 45) devDependencies에 typescript와 @types 추가하기
npm(node package manager)
은 자바스크립트 라이브러리 저장소와 프로젝트가 의존하고 있는 라이브러리들의 버전을 지정하는 방법을 제공함
의존성의 종류
- 세 가지 종류의 의존성을 구분해서 관리하며, 각각의 의존성은
package.json
파일 내의 별도 영역에 존재함dependencies
- 현재 프로젝트를 실행하는 데 필수적인 라이브러리들이 포함됨
- 프로젝트를 npm에 공개하여 다른 사용자가 해당 프로젝트를 설치한다면,
dependencies
에 들어 있는 라이브러리도 함께 설치됨(전의 의존성)
devDependencies
- 현재 프로젝트를 개발하고 테스트하는 데 사용되지만, 런타임에는 필요 없는 라이브러리들이 포함됨
- ex) 테스트 프레임워크
- 프로젝트를 npm에 공개하여 다른 사용자가 해당 프로젝트를 설치한다면, devDependencies에 포함된 라이브러리들은 제외됨
- 현재 프로젝트를 개발하고 테스트하는 데 사용되지만, 런타임에는 필요 없는 라이브러리들이 포함됨
peerDependencies
- 런타임에 필요하긴 하지만, 의존성을 직접적으로 관리하지 않는 라이브러리들이 포함됨
- ex) 플러그인
- 런타임에 필요하긴 하지만, 의존성을 직접적으로 관리하지 않는 라이브러리들이 포함됨
타입스크립트는 개발 도구일뿐이고 타입 정보는 런타임에 존재하지 않으므로, 타입스크립트와 관련된 라이브러리는 일반적으로 devDependencies에 속함
공통적으로 고려해야할 의존성
타입스크립트 자체 의존성 고려
- 팀원들 모두가 항상 동일한 버전을 설치한다는 보장이 없음
- 프로젝트를 셋업할 때 별도의 단계가 추가됨
- 따라서 타입스크립트를
devDependencies
에 넣는 것이 좋음 - 대부분의 타입스크립트 IDE와 빌드 도구는
devDependencies
를 통해 설치된 타입스크립트의 버전을 인식할 수 있도록 되어 있음 ⭐⭐⭐⭐⭐- 또한 커맨드 라인에서
npx
명령어를 사용해devDependencies
를 통해 설치된 타입스크립트 컴파일러를 실행할 수 있음 ⭐
- 또한 커맨드 라인에서
devDependencies
에 포함되어 있다면,npm install
을 실행할 때 팀원들 모두 항상 정확한 버전의 타입스크립트를 설치할 수 있음타입 의존성(@types)을 고려해야 함
DefinitelyTyped
(타입스크립트 커뮤니티에서 유지보수하고 있는 자바스크립트 라이브러리의 타입을 정의한 모음)의 타입 정의들을npm
레지스트리의@types
스코프에 공개됨원본 라이브러리 자체가
dependencies
에 있더라도@types
의존성은devDependencies
에 있어야 함ex) 리액트의 타입 선언과 의존성 추가
npm install react npm install @types/react
Item 46) 타입 선언과 관련된 세 가지 버전 이해하기
- 의존성 관리는 개발자에게 매우 힘든 일이므로, 단순히 라이브러리의 전이적 의존성이 호환되는지 깊게 생각하지 않았을 경우가 흔함
세 가지 고려 사항
- 라이브러리의 버전
- 타입 선언(@types)의 버전
- 타입스크립트의 버전
세 가지 버전 중 하나라도 맞지 않으면, 의존성과 상관없어 보이는 곳에서 엉뚱한 오류가 발생할 수 있음
- 라이브러리 관리의 복잡한 메커니즘을 이해하는 것이 중요함
타입스크립트에서 일반적으로 의존성을 사용하는 방식은 다음과 같음
npm install react # react@16.8.6 npm install @types/react # @types/react@16.8.19
- 메이저 버전과 마이너 버전이 일치하지만 패치 버전은 일치하지 않음
- 타입 선언 자체에도 버그나 누락이 존재할 수 있으며, 앞선 예제의 경우 라이브러리 자체보다 타입 선언에 더 많은 업데이트가 있음
라이브러리와 타입 정보 버전이 별도로 관리되는 방식의 단점
라이브러리를 업데이트했으나 실수로 타입 선언은 업데이트하지 않은 경우
- 라이브러리 업데이트와 관련된 새로운 기능을 사용하려 할 때마다 타입 오류가 발생하여 런타임 오류 발생이 야기됨
- 보강 기법을 활용하여, 사용하려는 새 함수와 메서드의 타입 정보를 프로젝트 자체에 추가
라이브러리보다 타입 선언의 버전이 최신인 경우
- 타입 선언 버전과 라이브러리의 버전 정보가 어긋나는 경우, 타입 체커는 최신 API 기준으로 코드를 검사하지만 런타임에 실제로 쓰이는 것은 과거 버전일 수 있음
- 라이브러리와 타입 선언의 버전이 맞도록 라이브러리 버전을 올리거나 타입 버전을 내림
프로젝트에서 사용하는 타입스크립트 버전보다 라이브러리에서 필요로 하는 타입스크립트 버전이 최신인 경우
- 로대시, 리액트, 람다 같은 유명한 라이브러리의 타입 정보를 더 정확하게 표현하기 위해서 타입 시스템이 개선되고 버전이 올라가므로 타입스크립트 역시 최신 버전을 사용해야 함
declare module
선언으로 라이브러리의 타입 정보를 없애던가, 버전을 핸들링해야 함
@types
의존성이 중복되는 경우@types/foo
가@types/bar
에 의존하는 경우를 가정했을 때,@types/bar
가 현재 프로젝트와 호환되지 않는 버전의@types/foo
에 의존한다면npm
은 중첩된 폴더에 별도로 해당 버전을 설치하여 문제를 해결하려고 함- 전역 네임스페이스에 있는 타입 선언 모듈이라면 대부분 문제가 발생함
npm ls @types/foo
를 실행하여 어디서 타입 선언 중복이 발생했는지 추적할 수 있음- 버전 핸들링을 통해 서로 버전이 호환되게 하는 방식으로 해결
공식적인 권장사항은 라이브러리가 타입스크립트로 작성된 경우만 타입 선언을 라이브러리에 포함하고 자바스크립트로 작성된 라이브러리는 타입 선언을 DefinitelyTyped에 공개하여 커뮤니티에서 유지보수할 수 있게 맡기는 것이 좋음
Item 47) 공개 API에 등장하는 모든 타입을 export 하기
- 서드파티의 모듈에서 익스포트되지 않은 타입 정보가 필요한 경우가 생김
- 웬만하면 필요한 타입을 참조하는 방법을 찾을 수 있음
- 라이브러리 제작자는 프로젝트 초기에 타입
export
부터 작성해야 함- 만약 함수의 선언에 이미 타입 정보가 있다면 제대로
export
되고 있는 것이며, 타입 정보가 없다면 타입을 명시해야 함
- 만약 함수의 선언에 이미 타입 정보가 있다면 제대로
예제
interface SecretName {
first: string
last: string
}
interface SecretSanta {
name: SecretName
gift: string
}
export function getGift(name: SecretName, gift: string): SecretSanta {
// ...
}
해당 라이브러리 사용자는
SecretName
또는SecretSanta
를 직접import
할 수 없고,getGift
만import
가 가능함하지만 타입들은
export
된 함수 시그니처에 등장하기 때문에Parameter
와ReturnType
제너릭 타입을 사용해 추출할 수 있음type MySanta = ReturnType<typeof getGift> // SecretSanta type MyName = Parameters<typeof getGift>[0] // SecretName
공개 API 매개변수에 놓이는 순간 타입은 노출되므로 굳이 숨길 필요 없이, 라이브러리 사용자를 위해 명시적으로
export
하는 것이 좋음
Referenced
- 댄 밴더캄, 『이펙티브 타입스크립트』, 인사이트(2021.11.4), 229 ~ 239p