TypeScript型定義ファイルの書き方を徹底解説!declareやmoduleの使い方
生徒
「TypeScriptでライブラリを使おうとしたら、型がないと怒られてしまいました。型定義ファイルって自分で作れるんですか?」
先生
「それは困りましたね。TypeScriptには型定義ファイルという設計図のようなものがあり、declareやmoduleといったキーワードを使って自分で書くことができますよ。」
生徒
「難しそうですが、初心者でも書き方は覚えられますか?」
先生
「大丈夫です!ルールさえ分かれば簡単です。まずは基本から一緒に学んでいきましょう!」
1. 型定義ファイル(d.ts)とは何か
TypeScriptを学習していると、型定義ファイルという言葉をよく耳にします。これは、プログラムの中で使う変数や関数の型がどのようなものかを、あらかじめTypeScriptに教えてあげるための専用のファイルです。ファイルの拡張子が.d.tsとなっているのが特徴です。
プログラミング未経験の方に分かりやすく例えると、型定義ファイルは料理のレシピ本のようなものです。レシピ本には、どんな材料が必要で、どのような手順で料理を作るかが書かれています。これがあるおかげで、初めて料理をする人でも迷わずに作ることができます。TypeScriptにとっての型定義ファイルも同じで、プログラムがどのように動くべきかを示すガイドラインの役割を果たしています。
特に、JavaScriptで作られた古いライブラリをTypeScriptで使いたい場合、TypeScriptはその中身がどうなっているか分かりません。そこで、この型定義ファイルを用意して、このプログラムにはこういう名前の変数があって、それは数字ですよ、といった情報を補足してあげる必要があるのです。
2. declareキーワードの基本的な役割
型定義ファイルを書くときに最もよく使うのがdeclareというキーワードです。これは日本語に訳すと宣言するという意味になります。具体的には、この変数はどこか別の場所ですでに作られているから、TypeScriptはエラーを出さないでねと伝える役割を持っています。
例えば、HTMLの中で読み込んでいる外部のスクリプトで、userNameという変数が定義されているとします。TypeScriptファイルの中でいきなりこの変数を使おうとすると、そんな変数は知らないよと怒られてしまいます。そこで、次のように記述します。
declare const userName: string;
console.log(userName);
このように書くことで、TypeScriptに対して、この変数は後から実体が現れるから、今は型だけ覚えておいてと約束をすることができます。実体を作るのではなく、あくまで型だけを伝えるのがポイントです。パソコンを初めて触る方にとっては、透明な箱にラベルを貼っておくようなイメージだと考えると分かりやすいでしょう。中身は後で入れるけれど、この箱には文字が入る予定ですよとラベルを貼っておくのです。
3. moduleを使った外部ライブラリの型定義
次に紹介するのはdeclare moduleです。これは特定の名前を持つモジュール、つまりプログラムの部品の集まりに対して型を定義するときに使います。JavaScriptの世界では、たくさんの便利なプログラムがライブラリとして公開されていますが、中には型情報を持っていないものもあります。
そういった場合に、自分のプロジェクトの中でそのライブラリを使えるようにするために、モジュールの名前を指定して型を定義します。例えば、my-libraryという名前のライブラリを使いたいときは、以下のように書きます。
declare module "my-library" {
export function sayHello(name: string): void;
export const version: number;
}
これにより、my-libraryからsayHelloという関数を呼び出すときに、名前という文字を渡す必要があることや、返り値がないことをTypeScriptが理解してくれます。モジュールとは、家の中に例えると子供部屋やキッチンといった独立した空間のようなものです。それぞれの部屋にどんな道具があるのかを定義するのが、この書き方の役割です。
4. globalを使ってどこからでも使える型を作る
プログラム全体で、どこからでもアクセスできる共通の型を作りたい場合があります。これをグローバルな型と呼びます。通常、TypeScriptではファイルごとに型が分かれていますが、declare globalを使うことで、どのファイルからでも参照できる型を定義できます。
例えば、ブラウザのwindowオブジェクトに、自分独自のプロパティを追加したい場合などに非常に便利です。以下のコードを見てみましょう。
declare global {
interface Window {
myAppConfig: {
theme: string;
isDarkMode: boolean;
};
}
}
これを定義しておくと、プログラムのどこでもwindow.myAppConfig.themeといった形で、入力候補が表示されるようになります。グローバルとは、学校の全校放送のようなものです。一つの場所で定義した内容が、学校中のすべての教室に届くようになります。非常に便利ですが、どこからでも変更できてしまうため、使いすぎには注意が必要です。
5. DefinitelyTypedとは何かを知ろう
自分で型定義ファイルを書く方法を学びましたが、実は世界中の開発者がすでに作ってくれた型定義ファイルが大量に公開されています。その集まりがDefinitelyTypedと呼ばれる巨大なリポジトリです。私たちはこれを@typesという名前で利用しています。
例えば、有名なライブラリであるjQueryを使いたいとき、自分で型を書かなくても、ターミナルでコマンドを打つだけで型定義ファイルを手に入れることができます。これは、巨大な図書館のようなものです。自分が読みたい本の解説書がすでに誰かによって書かれていて、それを借りてくるだけで自分のTypeScript環境が賢くなるのです。
初心者のうちは、まずはこの@typesで提供されているものがないか探し、どうしても見つからない場合に自分で型定義ファイルを書くという流れが一般的です。まずは既存の素晴らしい知識を活用することを覚えましょう。
6. interfaceとtypeの使い分け
型定義ファイルの中で、オブジェクトの形を定義するときによく使われるのがinterfaceとtypeです。どちらも型に名前をつけるためのものですが、少しだけ性格が違います。
interfaceは後から拡張することが得意です。例えば、一度決めたルールに後から付け足しをしたい場合はinterfaceを使います。一方で、typeはより厳格で、複数の型を組み合わせたりする複雑な定義に向いています。初心者のうちは、まずはinterfaceを使って、ものの形を決めることに慣れていくのがおすすめです。
interface UserProfile {
id: number;
name: string;
email?: string;
}
const user: UserProfile = {
id: 1,
name: "テツ太郎"
};
上記の例では、emailの後にハテナマークが付いています。これは、メールアドレスがあってもなくても大丈夫という意味です。このように、柔軟なルール作りができるのもTypeScriptの魅力の一つです。プログラミングの道具箱を整理するように、一つずつ型を定義していきましょう。
7. namespaceを使った名前の整理整頓
大きなプログラムを作っていると、同じ名前の関数や型が重なってしまうことがあります。これを名前の衝突と呼びます。これを防ぐために使われるのがnamespaceです。これは日本語で名前空間と呼びます。
イメージとしては、苗字のようなものです。同じ太郎さんでも、佐藤さんの家の太郎さんと、田中さんの家の太郎さんは別の人ですよね。それと同じで、namespaceを使うことで型をグループ分けして管理することができます。
declare namespace MyAppTools {
function cleanData(data: string): string;
function validateInput(input: number): boolean;
}
このように定義すると、MyAppTools.cleanData()という形で呼び出すことになり、他の場所にある同じ名前の関数と混ざる心配がなくなります。整理整頓がしっかりされている家は住み心地が良いように、名前空間で整理されたプログラムは、後から読み返したときにも分かりやすくなります。
8. 実際に型定義ファイルをプロジェクトに導入する手順
型定義ファイルの書き方が分かったら、次はそれをどうやってTypeScriptに認識させるかを知る必要があります。通常は、プロジェクトのルートフォルダにtypesといったフォルダを作成し、その中にindex.d.tsという名前でファイルを保存します。
その後、TypeScriptの設定ファイルであるtsconfig.jsonの中で、そのフォルダを読み込むように指定します。これで、書いた型定義がプロジェクト全体で有効になります。初めてパソコンで設定ファイルをいじるのは緊張するかもしれませんが、一回覚えてしまえば、あとはコピーして使い回すことができます。
もし設定がうまくいかないときは、まずはファイルの名前が.d.tsで終わっているかを確認してください。たった一文字の違いで動かなくなるのがプログラミングの厳しいところですが、それを乗り越えたときにプログラムが正しく動く喜びは格別です。焦らず、一つ一つの工程を丁寧に進めていきましょう。
9. 型定義ファイルを学ぶことで広がる可能性
型定義ファイルを自分で書けるようになると、TypeScriptの真の力を引き出すことができるようになります。既存のJavaScript資産を安全に使いこなせるだけでなく、自分たちが作ったプログラムの品質を保つための強力な武器になります。エラーを未然に防ぎ、開発のスピードを上げることができるのです。最初は難しく感じるかもしれませんが、基礎を固めていけば必ず理解できるようになります。