大まかに言うと、宣言ファイルをどのように構造化するかは、ライブラリがどのように消費されるかによって異なります。JavaScriptでライブラリを消費するために提供する方法はたくさんあり、それに対応する宣言ファイルを作成する必要があります。このガイドでは、一般的なライブラリパターンを識別する方法と、そのパターンに対応する宣言ファイルを記述する方法について説明します。
主要なライブラリ構造化パターンの各タイプには、テンプレートセクションに対応するファイルがあります。これらのテンプレートから始めて、より早く作業を開始できます。
ライブラリの種類を識別する
まず、TypeScriptの宣言ファイルが表現できるライブラリの種類を確認します。各ライブラリの種類がどのように使用され、どのように記述されるかを簡単に示し、実世界の例となるライブラリをいくつかリストします。
ライブラリの構造を識別することは、その宣言ファイルを記述する最初のステップです。使い方とコードの両方に基づいて構造を識別する方法のヒントを提供します。ライブラリのドキュメントと編成によっては、どちらか一方が他方よりも簡単な場合があります。より快適な方を使用することをお勧めします。
何を探すべきか?
型を付けようとしているライブラリを見ているときに自問する質問。
-
ライブラリをどのように入手しますか?
たとえば、npmからのみ、またはCDNからのみ取得できますか?
-
どのようにインポートしますか?
グローバルオブジェクトを追加しますか?
require
またはimport
/export
ステートメントを使用しますか?
さまざまな種類のライブラリの小さなサンプル
モジュールライブラリ
ほとんどすべての最新のNode.jsライブラリはモジュールファミリに該当します。これらのタイプのライブラリは、モジュールローダーを備えたJS環境でのみ機能します。たとえば、express
はNode.jsでのみ機能し、CommonJSのrequire
関数を使用してロードする必要があります。
ECMAScript 2015(ES2015、ECMAScript 6、ES6とも呼ばれます)、CommonJS、RequireJSは、モジュールをインポートするという同様の概念を持っています。たとえば、JavaScript CommonJS(Node.js)では、次のように記述します。
js
var fs = require("fs");
TypeScriptまたはES6では、import
キーワードが同じ目的を果たします
ts
import * as fs from "fs";
通常、モジュールライブラリのドキュメントには、これらの行のいずれかが含まれています。
js
var someLib = require("someLib");
または
js
define(..., ['someLib'], function(someLib) {});
グローバルモジュールと同様に、UMDモジュールのドキュメントでこれらの例を見つけることがあるため、コードまたはドキュメントを確認してください。
コードからモジュールライブラリを識別する
モジュールライブラリには、通常、少なくとも以下のいずれかが含まれます。
require
またはdefine
の無条件呼び出しimport * as a from 'b';
やexport c;
のような宣言exports
またはmodule.exports
への代入
めったに以下は含まれません。
window
またはglobal
のプロパティへの代入
モジュールのテンプレート
モジュールには、module.d.ts
、module-class.d.ts
、module-function.d.ts
、module-plugin.d.ts
の 4 つのテンプレートがあります。
まず、すべての動作方法の概要について、module.d.ts
をお読みください。
次に、モジュールが関数のように呼び出すことができる場合は、module-function.d.ts
テンプレートを使用します。
js
const x = require("foo");// Note: calling 'x' as a functionconst y = x(42);
モジュールが new
を使用して構築できる場合は、module-class.d.ts
テンプレートを使用します。
js
const x = require("bar");// Note: using 'new' operator on the imported variableconst y = new x("hello");
インポート時に他のモジュールを変更するモジュールがある場合は、module-plugin.d.ts
テンプレートを使用します。
js
const jest = require("jest");require("jest-matchers-files");
グローバルライブラリ
グローバルライブラリとは、グローバルスコープからアクセスできるライブラリ(つまり、import
の形式を使用せずに)のことです。多くのライブラリは、使用するために1つ以上のグローバル変数を単に公開しています。たとえば、jQuery を使用している場合、$
変数はそれを参照するだけで使用できます。
ts
$(() => {console.log("hello!");});
通常、グローバルライブラリのドキュメントには、HTML スクリプトタグでライブラリを使用する方法に関するガイダンスが記載されています。
html
<script src="http://a.great.cdn.for/someLib.js"></script>
今日、最も一般的なグローバルアクセス可能なライブラリは、実際には UMD ライブラリとして記述されています(下記参照)。UMD ライブラリのドキュメントは、グローバルライブラリのドキュメントと区別するのが困難です。グローバル宣言ファイルを作成する前に、ライブラリが実際には UMD ではないことを確認してください。
コードからグローバルライブラリを識別する
グローバルライブラリのコードは通常非常にシンプルです。グローバルの「Hello, world」ライブラリは、次のようになります。
js
function createGreeting(s) {return "Hello, " + s;}
または、次のようになります。
js
// Webwindow.createGreeting = function (s) {return "Hello, " + s;};// Nodeglobal.createGreeting = function (s) {return "Hello, " + s;};// Potentially any runtimeglobalThis.createGreeting = function (s) {return "Hello, " + s;};
グローバルライブラリのコードを見ると、通常は次のようになります。
- トップレベルの
var
ステートメントまたはfunction
宣言 window.someName
への 1 つ以上の代入document
やwindow
などの DOM プリミティブが存在するという前提
以下は表示されません。
require
やdefine
などのモジュールローダーのチェックまたは使用var fs = require("fs");
形式の CommonJS/Node.js スタイルのインポートdefine(...)
の呼び出し- ライブラリを
require
またはインポートする方法を説明するドキュメント
グローバルライブラリの例
通常、グローバルライブラリを UMD ライブラリに変換するのは簡単であるため、グローバルスタイルで記述された人気のあるライブラリはほとんどありません。ただし、小さくて DOM を必要とするライブラリ(または依存関係がないライブラリ)は、グローバルなままである可能性があります。
グローバルライブラリテンプレート
テンプレートファイル global.d.ts
は、ライブラリ myLib
の例を定義します。「名前の競合を防ぐ」の脚注を必ずお読みください。
UMD
UMD モジュールとは、モジュールとして(インポートを介して)またはグローバルとして(モジュールローダーのない環境で実行した場合)使用できるモジュールのことです。Moment.js など、多くの人気のあるライブラリがこの方法で記述されています。たとえば、Node.js または RequireJS では、次のように記述します。
ts
import moment = require("moment");console.log(moment.format());
一方、プレーンなブラウザ環境では、次のように記述します。
js
console.log(moment.format());
UMDライブラリを識別する
UMD モジュールは、モジュールローダー環境の存在を確認します。これは、次のような簡単に判別できるパターンです。
js
(function (root, factory) {if (typeof define === "function" && define.amd) {define(["libName"], factory);} else if (typeof module === "object" && module.exports) {module.exports = factory(require("libName"));} else {root.returnExports = factory(root.libName);}}(this, function (b) {
ライブラリのコードで、特にファイルの先頭に typeof define
、typeof window
、または typeof module
のテストが表示される場合は、ほとんどの場合 UMD ライブラリです。
UMD ライブラリのドキュメントでは、require
を示す「Node.js での使用」の例と、スクリプトをロードするための <script>
タグを使用する「ブラウザでの使用」の例もよく示されています。
UMDライブラリの例
現在、ほとんどの人気ライブラリは UMD パッケージとして入手できます。例としては、jQuery、Moment.js、lodash などがあります。
テンプレート
module-plugin.d.ts
テンプレートを使用します。
依存関係を消費する
ライブラリには、いくつかの種類の依存関係がある可能性があります。このセクションでは、宣言ファイルにインポートする方法を示します。
グローバルライブラリへの依存関係
ライブラリがグローバルライブラリに依存している場合は、/// <reference types="..." />
ディレクティブを使用します。
ts
/// <reference types="someLib" />function getThing(): someLib.thing;
モジュールへの依存関係
ライブラリがモジュールに依存している場合は、import
ステートメントを使用してください。
ts
import * as moment from "moment";function getThing(): moment;
UMDライブラリへの依存関係
グローバルライブラリから
グローバルライブラリがUMDモジュールに依存している場合は、/// <reference types
ディレクティブを使用してください。
ts
/// <reference types="moment" />function getThing(): moment;
モジュールまたはUMDライブラリから
モジュールまたはUMDライブラリがUMDライブラリに依存している場合は、import
ステートメントを使用してください。
ts
import * as someLib from "someLib";
UMDライブラリへの依存関係を宣言するために /// <reference
ディレクティブを使用しないでください!
脚注
名前の衝突の回避
グローバル宣言ファイルを作成する際に、グローバルスコープで多くの型を定義できることに注意してください。多くの宣言ファイルがプロジェクトにある場合、解決できない名前の衝突が発生する可能性があるため、これは強く推奨されません。
従うべき簡単なルールは、ライブラリが定義するグローバル変数によって名前空間化された型のみを宣言することです。たとえば、ライブラリがグローバル値 'cats' を定義している場合、次のように記述する必要があります。
ts
declare namespace cats {interface KittySettings {}}
しかし、そうではない
ts
// at top-levelinterface CatsKittySettings {}
このガイダンスは、宣言ファイルユーザーを壊すことなく、ライブラリをUMDに移行できることも保証します。
モジュール呼び出しシグネチャに対するES6の影響
Expressなどの多くの一般的なライブラリは、インポートされると呼び出し可能な関数として公開されます。たとえば、典型的なExpressの使用法は次のようになります。
ts
import exp = require("express");var app = exp();
ES6に準拠したモジュールローダーでは、トップレベルオブジェクト(ここではexp
としてインポート)はプロパティのみを持つことができます。トップレベルのモジュールオブジェクトは、決して呼び出し可能にすることはできません。
ここでの最も一般的な解決策は、呼び出し可能/構築可能なオブジェクトのdefault
エクスポートを定義することです。モジュールローダーは通常、この状況を自動的に検出し、トップレベルオブジェクトをdefault
エクスポートに置き換えます。tsconfig.jsonで"esModuleInterop": true
を設定している場合、TypeScriptはこれを処理できます。