ウェブエンジニア問題集
第12章

型定義ファイル(.d.ts)と@types

6
この章の目次開く

JavaScriptで書かれたライブラリをTypeScriptから使うとき、型情報が必要です。型定義ファイル(.d.ts)がその橋渡しをします。

学習者学習者

ライブラリを入れたら「型定義が見つかりません」って怒られた…。@types/... って何者なの?

先生先生

JSで書かれたライブラリには型情報がない。@types パッケージはコミュニティが作った「後付けの型定義」だよ。ライブラリ本体が最初からTSで書かれていれば不要なんだけどね。

.d.tsファイルとは

.d.ts ファイルは型情報だけを記述したファイルです。実行時のJavaScriptコードは含まず、TypeScriptコンパイラが型チェックに使います。

// example.d.ts
export declare function formatDate(date: Date, format: string): string;
export declare const VERSION: string;
typescript

declare キーワードは「この関数/変数は別の場所で実装されている」ことを表します。.d.ts は実装ではなく契約書のようなものです。

@typesパッケージ — DefinitelyTyped

JavaScriptで書かれたライブラリに型定義がない場合、コミュニティがDefinitelyTypedリポジトリで型定義を管理しています。

npm install --save-dev @types/react @types/node @types/express
bash

TypeScriptは node_modules/@types/ 配下を自動的に参照するため、インストールするだけで型が効きます。

型定義が同梱されているライブラリ

すべてのライブラリに @types が必要なわけではありません。ライブラリ本体に .d.ts が含まれている場合は不要です。

# @types 不要 — ライブラリ本体に型定義が含まれている
npm install zod        # TypeScriptで書かれている
npm install axios      # .d.ts が同梱されている
npm install date-fns   # TypeScriptで書かれている
bash

見分け方は、ライブラリの package.json"types" または "typings" フィールドがあるかどうかです。

// axiosの package.json(抜粋)
{
  "types": "./index.d.ts"
}
json

型定義がないライブラリへの対処

@types パッケージも存在しないライブラリの場合、declare module で最低限の型定義を書きます。

// src/types/some-legacy-lib.d.ts
declare module 'some-legacy-lib' {
  export function doSomething(input: string): void;
  export default class Client {
    constructor(apiKey: string);
    fetch(url: string): Promise<unknown>;
  }
}
typescript

すべてのAPIを詳細に型付けする必要はありません。自分が使う部分だけ定義すれば十分です。

学習者学習者

型定義を書くのが面倒なときは any で逃げてもいい?

先生先生

最初は any で通して動くようにして、あとから少しずつ型を付けていくのが現実的。ただし any を使った箇所はコメントや TODO で記録しておくと、後で見つけやすいよ。

最小限の型定義で any を使う場合:

// src/types/some-legacy-lib.d.ts
declare module 'some-legacy-lib' {
  const content: any;
  export default content;
}
typescript

グローバル型定義

プロジェクト全体で使う型を global.d.ts に定義できます。

// src/types/global.d.ts
 
// 環境変数の型定義
declare namespace NodeJS {
  interface ProcessEnv {
    DATABASE_URL: string;
    NEXT_PUBLIC_API_URL: string;
    NODE_ENV: 'development' | 'production' | 'test';
  }
}
 
// Window オブジェクトの拡張
interface Window {
  gtag: (...args: unknown[]) => void;
}
typescript
型定義の管理
型定義ファイルはsrc/types/に集めておくとプロジェクトの見通しがよくなる

環境変数の型を定義しておくと、process.env.DATABASE_URLstring として推論され、undefined チェックが不要になります。

型定義ファイルの配置

型定義ファイルは tsconfig.jsoninclude に含まれるパスに置きます。

src/
  types/
    global.d.ts        ← グローバル型定義
    some-legacy-lib.d.ts ← ライブラリの型定義
    api-response.ts    ← アプリの型定義(通常の .ts)

ちゃんと使うためのポイント

  • .d.ts は型情報だけのファイル。実装は含まない
  • @types/xxx はコミュニティ管理の型定義。ライブラリ本体に型があれば不要
  • 型定義がないライブラリは declare module で最低限の型を書く
  • 環境変数や Window の拡張はグローバル型定義で対応する
  • 自アプリの型定義は .ts、外部ライブラリの型付けは .d.ts で書く

参考リンク

TypeScriptクイズに挑戦するこの章で学んだTypeScriptの知識を、4択クイズでアウトプットして定着させよう