Featured image of post npmライブラリを公開するための型定義ファイル(.d.ts)出力設定 Featured image of post npmライブラリを公開するための型定義ファイル(.d.ts)出力設定

npmライブラリを公開するための型定義ファイル(.d.ts)出力設定

tsconfigのdeclarationプロパティの使い方、パッケージ配布時のpackage.jsonのtypes/exportsキーの安全な書き方を解説します。

型定義ファイルの重要性

TypeScript で書かれた npm パッケージを公開するとき、利用者が IntelliSense やコンパイル時チェックを得るには型情報が必要です。.d.ts ファイルがないとライブラリの型は実質的に any になり、TypeScript を使う意味が半減します。

型定義ファイルは、実装ソースを出荷せずにエクスポートの形状を記述します。ツリーシェイキング、ホバー時のドキュメント表示、利用者側での厳格な型チェックを可能にします。

.d.ts の生成

tsconfig.jsondeclarationtrue に設定すると、TypeScript コンパイラが宣言ファイルを生成します。

{
  "compilerOptions": {
    "declaration": true,
    "declarationMap": true,
    "emitDeclarationOnly": true,
    "outDir": "./dist",
    "rootDir": "./src"
  }
}
オプション目的
declaration.js と共に .d.ts を出力
declarationMap宣言のソースマップを生成(エディタの定義へ移動に対応)
emitDeclarationOnly宣言のみ出力(JS の出力は別のツールに任せる場合)
outDirJS と .d.ts の出力先ディレクトリ
npx tsc

出力構造は src/ のレイアウトを反映します。src/index.ts から dist/index.jsdist/index.d.ts が生成されます。

Package.json の types フィールド

types フィールド(別名 typings)はエントリとなる宣言ファイルを指します。

{
  "name": "my-library",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts"
}

ESM/CJS デュアルパッケージ の場合は、exports フィールドで条件付き解決を提供します。

{
  "exports": {
    ".": {
      "import": {
        "types": "./dist/index.d.mts",
        "default": "./dist/index.mjs"
      },
      "require": {
        "types": "./dist/index.d.ts",
        "default": "./dist/index.js"
      }
    }
  }
}

これにより TypeScript は import 文では index.d.mts を、require() では index.d.ts を読み込みます。

トリプルスラッシュディレクティブ

手書きのアンビエント宣言では、トリプルスラッシュディレクティブを使って他の型を参照します。

/// <reference types="node" />
/// <reference path="./custom-types.d.ts" />

export function readConfig(path: string): Buffer;

これらは .d.ts ファイルでのみ有効で、実装 .ts ファイルでは使えません。生成された宣言では通常の import 文を使いましょう。

パッケージに宣言ファイルを含める

package.jsonfiles フィールドで npm 公開時に含めるファイルを制御します。

{
  "files": [
    "dist",
    "!dist/**/*.test.d.ts",
    "README.md",
    "LICENSE"
  ]
}

テスト用の宣言ファイルやソース .ts ファイルは公開対象から除外しましょう。

宣言のテスト

公開前に、利用者が正しく型を解決できることを確認します。

mkdir test-consumer && cd test-consumer
npm init -y
npm link ../my-library
import { MyType } from "my-library";

const x: MyType = { /* ... */ };

テストプロジェクトで npx tsc --noEmit を実行し、エラーなくコンパイルできれば成功です。

よくある問題

問題解決策
.js に対応する .d.ts がないdeclaration: true を設定
利用者側で型が any になるtypes フィールドが正しいエントリを指しているか確認
ESM/CJS の型が解決されないexports に個別の types 条件を記述
宣言のソースマップが機能しないdeclarationMap: true を追加
プライベート型が公開 API に漏れる内部型の先頭に _ を付けるか @internal JSDoc タグを使用

まとめ

型定義ファイルを正しく生成・公開することで、TypeScript ライブラリはファーストクラスの開発体験を提供できます。tsconfig で declaration: true を設定し、package.json で types フィールドを指定し、デュアルモジュールパッケージには exports を使い、公開前に必ず利用者プロジェクトで検証しましょう。