型定義ファイル (.d.ts)
自身のプロジェクトでTypeScriptでコーディングする場合は型を宣言することにより、IDEやエディターの補完機能やコードチェックを行えます。しかし外部のパッケージ(npm)を利用する場合は型定義ファイルが含まれているとは限りません。
型定義ファイルとは
型定義ファイルとはアクセス可能な宣言を記述したファイルです。拡張子は
.d.ts
です。
型定義ファイルは主にパッケージを配布するために作成されます。TypeScriptはJavaScriptにコンパイルされるときに型情報は無くなってしまいます。そのままJavaScriptパッケージを利用すると型定義の恩恵を得ることができません。しかし型定義ファイルを同梱することにより補完やコードチェックとして利用することができます。
残念なことにnpmに公開されているすべてのパッケージに必ずしも定義ファイルが存在するとは限りません。こちらに関しては 型定義ファイルの有無 にて説明します。
型定義ファイル出力例
tscコマンドに
-d
オプションをつけてコンパイルを行うとJavaScriptと型定義ファイルを出力することができます。
TypeScriptファイル
次のTypeScriptファイル(sample.ts)を
-d
オプションを付けてコンパイルしてみます。
sample.tstsinterfacePerson {firstName : string;lastName : string;}functiongreeter (person :Person ): string {return "Hello, " +person .firstName + " " +person .lastName ;}
sample.tstsinterfacePerson {firstName : string;lastName : string;}functiongreeter (person :Person ): string {return "Hello, " +person .firstName + " " +person .lastName ;}
tscコマンドに
-d
オプションを付けコンパイルを実行する。
bashtsc -d
bashtsc -d
JavaScriptファイル
sample.tsではInterfaceを使っていますが、JavaScriptにはInterfaceの概念がないため関数のみになりました。また引数の型情報もなくなります。
sample.jsjsfunctiongreeter (person ) {return "Hello, " +person .firstName + " " +person .lastName ;}//# sourceMappingURL=sample.js.map
sample.jsjsfunctiongreeter (person ) {return "Hello, " +person .firstName + " " +person .lastName ;}//# sourceMappingURL=sample.js.map
d.ts
ファイル
定義情報のみ記載されたファイルが出力されます。
sample.d.tstsinterfacePerson {firstName : string;lastName : string;}declare functiongreeter (person :Person ): string;
sample.d.tstsinterfacePerson {firstName : string;lastName : string;}declare functiongreeter (person :Person ): string;
型定義ファイルの有無
型定義ファイルはパッケージ開発者またはボランティアにより作成されています。
-
型定義ファイル有り
- TypeScriptで書かれたパッケージ
-
JavaScriptで書かれたパッケージだが
.d.tsファイルを同梱している
-
型定義ファイル有りだが別途インストールが必要
- JavaScriptで書かれたパッケージだが、 DefinitelyTypedに登録されている
-
型定義ファイル無し
- JavaScriptで書かれたパッケージで型定義ファイルが存在しない
型定義ファイル有り
NPMのパッケージの紹介ページを見るとパッケージ名称の右にTSのアイコンが表示されている場合があります。これは型定義ファイルが存在することを示しています。
これは、パッケージ開発者がTypeScriptで開発しているか、JavaScriptで開発しているが型定義ファイルを同梱していることを示しています。型定義ファイルが含まれているパッケージの場合は特別な作業は必要ありません。
例としてdate libraryの
date-fns
はJavaScriptで構築されていますが、
typings.d.ts
を同封しています。そのままinstallを行うだけで定義ファイルの恩恵を受けられます。
bashnpm install date-fns
bashnpm install date-fns
型定義ファイル有りの場合は、設定なく型情報を参照することができます。
型定義ファイル有りだが別途インストールが必要
NPMのパッケージの紹介ページを見るとパッケージ名称の右にDTのアイコンが表示されている場合があります。これは型定義ファイルがこのパッケージ自身には含まれていないが、
DefinitelyTyped
に登録されていることを示しています。
この場合は、パッケージをインストールした後に別途型定義ファイルをインストールする必要があります。定義ファイルのインストールも
npm
コマンドを利用します。
例として
Express
はJavaScriptで構築されていますが、型定義ファイルは
@types/express
というパッケージとして別途インストールする必要があります。
Express 本体と定義ファイルのインストール例は次のようになります。
bashnpm install express --save # express本体のインストールnpm install @types/express --save-dev # 型定義ファイルのインストール
bashnpm install express --save # express本体のインストールnpm install @types/express --save-dev # 型定義ファイルのインストール
型定義ファイル無し
型定義ファイルがないライブラリも存在します。その場合は
-
anyで妥協する - 型定義ファイルを作る
型定義ファイルの存在しないライブラリも利用することが可能ですが暗黙的に
any
型になります。また自身で作成しDefinitelyTypedに公開することもできます。
コントリビュート(貢献)する方法 | Definitely Typed
型定義ファイルで登場するキーワード
ここでは型定義ファイルを読めるようになるために、型定義ファイルでよく利用されるキーワードを紹介します。
declare
declare
キーワードを使うことでTypeScriptに変数、関数、クラスなどがJavaScript内に「存在する」ことを伝えることができます。これを「アンビエント宣言」と呼びます。
次のファイルがJavaScriptライブラリとして読み込まれており、グローバル関数として
hello
が使える状態だとします。
jsfunctionhello (name ) {return "Hello, " +name ;}
jsfunctionhello (name ) {return "Hello, " +name ;}
この状態でTypeScriptで
hello
関数を呼び出すと型エラーが発生します。これは、TypeScriptが
hello
関数が存在することを知らないためです。
tsCannot find name 'hello'.2304Cannot find name 'hello'.("taro"); hello
tsCannot find name 'hello'.2304Cannot find name 'hello'."taro"); hello (
declare
を利用してアンビエント宣言をすることで、TypeScriptにJavaScript内のどこかに
hello
関数が「存在する」ことを宣言することができます。これによりTypeScriptが
hello
関数を認識できるようになります。
tsdeclare functionhello (name : string): string;hello ("taro");
tsdeclare functionhello (name : string): string;hello ("taro");
実際のモジュールの型定義ファイルの例として
jest
の型定義ファイルを見てみましょう。
beforeAll
などの関数が型定義ファイル内でアンビエント宣言されているのが確認できます。これによりモジュールの読み込みをしなくても、TypeScriptが
beforeAll
を関数として認識することができます。
node_modules/@types/jest/index.d.tstsdeclare varbeforeAll :jest .Lifecycle ;declare namespacejest {typeLifecycle = (fn :ProvidesHookCallback ,timeout ?: number) => any;}
node_modules/@types/jest/index.d.tstsdeclare varbeforeAll :jest .Lifecycle ;declare namespacejest {typeLifecycle = (fn :ProvidesHookCallback ,timeout ?: number) => any;}
namespace
namespace
キーワードを使うことで名前空間を定義することができます。