Publishing

Publishing (npm으로 배포하기)

이 가이드의 과정을 따라 선언 파일을 작성했다면, 이제 그것을 npm에 배포할 차례예요. 선언 파일을 npm에 배포하는 방법은 크게 두 가지가 있습니다.

  1. 자기 npm 패키지에 포함(bundling)시키기
  2. npm의 @types 조직에 배포하기

타입이 소스 코드에서 생성된다면 타입을 소스 코드와 함께 배포하세요. TypeScript 프로젝트와 JavaScript 프로젝트 모두 declaration으로 타입을 생성할 수 있어요.

그렇지 않다면 DefinitelyTyped에 제출할 것을 권장합니다. npm의 @types 조직에 배포되어요.

출처: TypeScript 핸드북

npm 패키지에 선언 포함하기

패키지에 main .js 파일이 있다면, package.json에 메인 선언 파일도 함께 지정해 줘야 해요. types 속성을 포함하고 있는 선언 파일을 가리키도록 설정하세요. 예를 들어:

{
  "name": "awesome",
  "author": "Vandelay Industries",
  "version": "1.0.0",
  "main": "./lib/main.js",
  "types": "./lib/main.d.ts"
}

"typings" 필드는 types와 동의어이며, 똑같이 사용될 수 있다는 점을 참고하세요.

의존성 (Dependencies)

모든 의존성은 npm이 관리해요. 의존하는 모든 선언 패키지가 package.json"dependencies" 섹션에 알맞게 표시되도록 하세요. 예를 들어 Browserify와 TypeScript를 사용하는 패키지를 작성했다고 해 볼게요.

{
  "name": "browserify-typescript-extension",
  "author": "Vandelay Industries",
  "version": "1.0.0",
  "main": "./lib/main.js",
  "types": "./lib/main.d.ts",
  "dependencies": {
    "browserify": "latest",
    "@types/browserify": "latest",
    "typescript": "next"
  }
}

여기서 우리 패키지는 browserifytypescript 패키지에 의존합니다. browserify는 선언 파일을 npm 패키지에 포함하지 않기 때문에, 그 선언을 위해 @types/browserify에 의존할 필요가 있었어요. 반면 typescript는 선언 파일을 패키지에 포함하므로 추가 의존성이 필요 없습니다.

우리 패키지는 그것들 각각의 선언을 노출하므로, browserify-typescript-extension 패키지의 사용자는 이 의존성들도 함께 가져야 해요. 그래서 "devDependencies"가 아니라 "dependencies"를 사용했어요. 그렇지 않으면 소비자가 그 패키지들을 수동으로 설치해야 하기 때문입니다. 만약 단순한 명령줄 애플리케이션을 작성했고 라이브러리로 사용될 것을 기대하지 않는다면, devDependencies를 썼을 수도 있어요.

주의해야 할 신호 (Red flags)

/// <reference path="..." />

선언 파일에서 /// <reference path="..." />사용하지 마세요.

/// <reference path="../typescript/lib/typescriptServices.d.ts" />
....

대신 /// <reference types="..." />사용하세요.

/// <reference types="typescript" />
....

자세한 내용은 의존성 사용하기 섹션을 다시 확인해 보세요.

의존하는 선언 패키징하기

타입 정의가 다른 패키지에 의존한다면:

  • 자기 것과 합치지 마세요. 각각 자기 파일에 두세요.
  • 선언을 자기 패키지에 복사하지도 마세요.
  • 그 패키지가 자기 선언 파일을 패키징하지 않는다면, npm 타입 선언 패키지에 의존하세요.

typesVersions로 버전 선택하기

TypeScript가 package.json 파일을 열어 어떤 파일들을 읽어야 할지 알아낼 때, 먼저 typesVersions라는 필드를 확인해요.

폴더 리다이렉트 (* 사용)

typesVersions 필드를 가진 package.json은 이렇게 생겼을 거예요.

{
  "name": "package-name",
  "version": "1.0.0",
  "types": "./index.d.ts",
  "typesVersions": {
    ">=3.1": { "*": ["ts3.1/*"] }
  }
}

package.json은 TypeScript에게 먼저 현재 TypeScript 버전을 확인하라고 지시해요. 3.1 이상이라면, TypeScript는 패키지에 상대적으로 import한 경로를 알아내서 패키지의 ts3.1 폴더에서 읽어들입니다.

그게 바로 { "*": ["ts3.1/*"] }이 뜻하는 것이에요. path 매핑에 익숙하다면, 정확히 그렇게 동작합니다.

위 예시에서 "package-name"에서 import한다면, TypeScript 3.1로 실행 중일 때 TypeScript는 [...]/node_modules/package-name/ts3.1/index.d.ts(및 기타 관련 경로)에서 해석하려고 시도해요. package-name/foo에서 import한다면 [...]/node_modules/package-name/ts3.1/foo.d.ts[...]/node_modules/package-name/ts3.1/foo/index.d.ts를 찾게 됩니다.

그럼 이 예시에서 TypeScript 3.1로 실행하지 않는다면 어떨까요? typesVersions의 어떤 필드도 매칭되지 않으면 TypeScript는 types 필드로 폴백하므로, 여기서 TypeScript 3.0 이하는 [...]/node_modules/package-name/index.d.ts로 리다이렉트됩니다.

파일 리다이렉트

한 번에 단일 파일에 대해서만 해석을 바꾸고 싶다면, 정확한 파일 이름을 전달해서 그 파일을 다르게 해석하도록 TypeScript에 알려줄 수 있어요.

{
  "name": "package-name",
  "version": "1.0.0",
  "types": "./index.d.ts",
  "typesVersions": {
    "<4.0": { "index.d.ts": ["index.v3.d.ts"] }
  }
}

TypeScript 4.0 이상에서는 "package-name"에 대한 import가 ./index.d.ts로 해석되고, 3.9 이하에서는 "./index.v3.d.ts로 해석돼요.

리다이렉션은 패키지의 외부 API에만 영향을 준다는 점을 참고하세요. 프로젝트 내부의 import 해석은 typesVersions의 영향을 받지 않습니다. 예를 들어 앞선 예시에서 import * as foo from "./index"를 포함한 d.ts 파일은 여전히 index.d.ts로 매핑되고 index.v3.d.ts로는 매핑되지 않는 반면, import * as foo from "package-name"을 import하는 다른 패키지는 index.v3.d.ts얻게 됩니다.

매칭 동작 (Matching behavior)

TypeScript가 컴파일러&언어의 버전이 매칭되는지 결정하는 방식은 Node의 semver 범위를 사용해요.

여러 필드 (Multiple fields)

typesVersions는 여러 필드를 지원하며, 각 필드 이름은 매칭할 범위로 지정합니다.

{
  "name": "package-name",
  "version": "1.0",
  "types": "./index.d.ts",
  "typesVersions": {
    ">=3.2": { "*": ["ts3.2/*"] },
    ">=3.1": { "*": ["ts3.1/*"] }
  }
}

범위는 겹칠 수 있기 때문에, 어떤 리다이렉트가 적용될지 결정하는 것은 순서에 따라 달라져요. 즉 위 예시에서는 >=3.2>=3.1 매처가 모두 TypeScript 3.2 이상을 지원하지만, 순서를 뒤집으면 동작이 달라질 수 있으므로 위 예시는 아래와 동일하지 않습니다.

{
  "name": "package-name",
  "version": "1.0",
  "types": "./index.d.ts",
  "typesVersions": {
    // NOTE: this doesn't work!
    ">=3.1": { "*": ["ts3.1/*"] },
    ">=3.2": { "*": ["ts3.2/*"] }
  }
}

@types에 배포하기

@types 조직 아래의 패키지는 types-publisher 도구를 사용해 DefinitelyTyped에서 자동으로 배포됩니다. 여러분의 선언을 @types 패키지로 배포하려면 DefinitelyTyped에 풀 리퀘스트를 제출하세요. 자세한 내용은 기여 가이드라인 페이지에서 확인할 수 있어요.

더 알아보기 (Learn more)