45. devDependencies에 typescript와 @types 추가하기
npm은 세 가지 종류의 의존성을 구분해서 관리하며, 각각의 의존성은 package.json 파일 내 별도 영역에 들어 있다.
- dependencies
현재 프로젝트를 실행하는 데 필수적인 라이브러리들이 포함된다.
lodash 같이 프로젝트의 런타임에 사용되는 라이브러리들이 포함되어야 한다.
npm에 공개하여 다른 사용자가 설치할 경우, dependencies에 들어 있는 라이브러리도 함께 설치된다. (전이 의존성) - devDependencies
현재 프로젝트를 개발하고 테스트하는 데 사용되지만, 런타임에는 필요 없는 라이브러리들이 포함된다.
트스트 프레임워크 같은 라이브러리들이 포함될 수 있다.
npm에 공개하여 다른 사용자가 설치할 경우, devDependencies에 포함된 라이브러리들은 제외된다. - peerDependencies
런타임에 필요하긴 하지만, 의존성을 직접 관리하지 않는 라이브러리들이 포함된다.
플러그인을 예시로 들 수 있다.
(제이쿼리의 플러그인은 다양한 버전의 제이쿼리와 호환되므로, 제이쿼리의 버전을 플러그인에서 직접 선택하지 않고,
플러그인이 사용되는 실제 프로젝트에서 선택하도록 만들 때 사용한다.)
모든 타입스크립트 프로젝트에서 공통적으로 고려해야 할 의존성 두 가지가 있다.
- 타입스크립트 자체 의존성
타입스크립트를 시스템 레벨로 설치하는 것은 추천하지 않는다.
팀원들 모두가 항상 동일한 버전을 선치한다는 보장도 없고, 프로젝트 셋업 시 별도의 단계가 추가되기 때문에
타입스크립트는 devDependencies에 넣는 것이 좋다. - 타입 의존성(@types)
npm 레지스트리의 @types 스코프에 공개된 DefinitelyTyped의 타입 정의들을 사용할 수 있다.
@types 의존성은 devDependencies에 있어야 한다.
46. 타입 선언과 관련된 세 가지 버전 이해하기
타입스크립트는 의존성 관리를 더 복잡하게 만든다. 타입스크립트를 사용하면 다음 사항을 고려해야 한다.
라이브러리의 버전
타입 선언(@types)의 버전
타입스크립트의 버전
세 가지 버전 중 하나라도 맞지 않으면 엉뚱안 오류가 발생할 수 있다.
실제 라이브러리와 타입 정보의 버전이 별도로 관리되는 방식은 다음 네 가지 문제점이 있다.
- 라이브러리를 업데이트 했지만 실수로 타입 선언은 업데이트하지 않을 수 있다.
- 라이브러리보다 타입 선언의 버전이 최신일 수 있다.
- 프로젝트에서 사용하는 타입스크립트 버전보다 라이브러리에서 필요로 하는 타입스크립트 버전이 최신일 수 있다.
- @types 의존성이 중복될 수 있다.
@types/foo와 @types/bar에 의존한다고 가정하자.
만약 @types/bar가 현재 프로젝트와 호환되지 않는 버전의 @types/foo에 의존한다면
npm은 중첩된 폴더에 별도로 해당 버전을 설치하여 문제를 해결하려고 한다.
런타임에 사용되는 모듈이라면 괜찮을 수 있지만, 전역 네임스페이스에 있는 타입 선언 모듈이라면 문제가 발생한다.
npm ls @types/foo를 실행하여 어디서 타입 선언 중복이 발생했는지 추적할 수 있다.
타입스크립트로 작성된 라이브러리들은 자체적으로 타입 선언을 포함(번들링)하게 된다.
자체적인 타입 선언은 보통 package.json의 "types" 필드에서 .d.ts 파일을 가리키도록 되어 있다.
타입스크립트로 작성된 라이브러리라면,
타입스크립트 컴파일러가 타입 선언을 대신 생성해 주기 때문에 타입 선언을 자체적을 포함하는 것이 좋다.
자바스크립트로 작성된 라이브러리라면,
타입 선언을 DefinitelyTyped에 공개하여 커뮤니티에서 관리하고 유지보수하도록 맡기는 것이 좋다.
47. 공개 API에 등장하는 모든 타입을 익스포트하기
서드파티의 모듈에서 익스포트되지 않은 타입 정보가 필요한 경우가 생긴다.
즉, 라이브러리 제작자는 프로젝트 초기에 타입 익스포트부터 작성해야 한다는 것이다.
interface SecretName {
first: string;
last: string;
}
interface SecretSanta {
name: SecretName;
gift: string;
}
export function getGift(name: SecretName, gift: string): SecretSanta {}
사용자는 SecretName과 SecretSanta를 직접 임포트할 수 없다.
그러나 타입들이 익스포트된 함수 시그니처에 등장하기 때문에 추출해 낼 수 있다.
type MySanta = ReturnType<typeof getGift>;
type MyName = Parameters<typeof getGift>[0];
일부러 익스포트하지 않았떤 것이라면 쓸데없는 짓을 한 셈이다.
공개 API 매개변수에 놓이는 순간 타입은 노출된다. 굳이 숨기려 하지 말고 명시적으로 익스포트하자.
48. API 주석에 TSDoc 사용하기
대부분의 편집기는 함수가 호출되는 곳에서 함수에 붙어 있는 JSDoc 스타일의 주석을 툴팁으로 표시해 주기 때문에,
사용자를 위한 문서라면 인라인 주석보다는 JSDoc 스타일의 주석으로 만드는 것이 좋다.
JSDoc에는 @param과 @returns를 추가할 수 있다.
타입 정의에 TSDoc을 사용할 수도 있으며, 마크다운 형식으로 꾸밀 수 있다.
타입스크립트에는 타입 정보가 코드에 있기 때문에, TSDoc에서는 타입 정보(@param과 @returns)를 명시하지 말자.