型定義ファイルの重要性
TypeScript で書かれた npm パッケージを公開するとき、利用者が IntelliSense やコンパイル時チェックを得るには型情報が必要です。.d.ts ファイルがないとライブラリの型は実質的に any になり、TypeScript を使う意味が半減します。
型定義ファイルは、実装ソースを出荷せずにエクスポートの形状を記述します。ツリーシェイキング、ホバー時のドキュメント表示、利用者側での厳格な型チェックを可能にします。
.d.ts の生成
tsconfig.json で declaration を true に設定すると、TypeScript コンパイラが宣言ファイルを生成します。
{
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": "./src"
}
}
| オプション | 目的 |
|---|---|
declaration | .js と共に .d.ts を出力 |
declarationMap | 宣言のソースマップを生成(エディタの定義へ移動に対応) |
emitDeclarationOnly | 宣言のみ出力(JS の出力は別のツールに任せる場合) |
outDir | JS と .d.ts の出力先ディレクトリ |
npx tsc
出力構造は src/ のレイアウトを反映します。src/index.ts から dist/index.js と dist/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.json の files フィールドで 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 を使い、公開前に必ず利用者プロジェクトで検証しましょう。
