lib.d.ts

lib.d.ts

特別な宣言ファイルlib.d.tsはTypeScriptをインストールしたときに付属しています。このファイルには、JavaScriptランタイムとDOMに存在するさまざまな一般的なJavaScriptを構成する機能のアンビエント宣言が含まれています。

  • このファイルは、TypeScriptプロジェクトのコンパイルコンテキストに自動的に含まれます

  • このファイルの目的は、JavaScriptやTypeScriptのプロジェクトで、すぐに型のサポートを得られるようにすることです

  • TypeScriptをサポートしているIDE(Visual Studio Code等)であれば、JavaScriptのプロジェクトであっても、型の恩恵を得ることができます

コンパイルオプションに--noLibを指定してこのファイルをコンパイルコンテキストから除外することができます(tsconfig.jsonnoLib : trueを指定)。

使用例

いつものように、実際に使用されている例を見てみましょう:

var foo = 123;
var bar = foo.toString();

このコードは問題なく型チェックされます。なぜなら、すべてのJavaScriptオブジェクトに対してtoString関数がlib.d.tsで定義されているからです。

noLibオプションで同じサンプルコードを使用すると、型チェックエラーが発生します:

var foo = 123;
var bar = foo.toString(); // ERROR: Property 'toString' does not exist on type 'number'.

これで、lib.d.tsの重要性を理解いただけたと思います。次にその内容を見てみましょう。

lib.d.tsの内容

lib.d.tsの内容は、主に変数宣言の集まりです。例えばwindowdocumentmathや、同様のインターフェース宣言WindowDocumentMathです。

このドキュメントと型アノテーションを読む一番簡単な方法は、動くとわかっているコードをエディターで打ち込んでみることです。例えばIDEでMath.floorと打ち込み、F12を押下すると、定義に移動します(VSCodeはこれをサポートしています)。

サンプルの変数宣言を見てみましょう。windowは次のように定義されます:

declare var window: Window;

この単純なdeclare varの後に、変数名(ここではwindow)とアノテーションで指定されているインターフェース(Windowインターフェース)が続きます。これらの変数は、一般的にグローバルなインターフェースを指し示しています。例として、ここにWindowインターフェースの小さな(実際には非常に大規模な)サンプルを提示します:

interface Window extends EventTarget, WindowTimers, WindowSessionStorage, WindowLocalStorage, WindowConsole, GlobalEventHandlers, IDBEnvironment, WindowBase64 {
    animationStartTime: number;
    applicationCache: ApplicationCache;
    clientInformation: Navigator;
    closed: boolean;
    crypto: Crypto;
    // so on and so forth...
}

これらのインターフェースには、たくさんの型情報があることがわかります。TypeScriptが存在しない場合、これを頭で覚えておかなければなりません。コンパイラが理解している知識を、インテリセンスや自動補完のようなもので容易にアクセスできるようにすることができます。

これらのグローバルにインターフェースを使用していることは良いことです。なぜなら、lib.d.tsを変更することなく、これらのグローバルのインターフェースにプロパティを追加することができるからです。次に、この概念について説明します。

ネイティブ型(Native Types)を変更する

TypeScriptのinterfaceはオープンエンドなので、lib.d.tsで宣言されたインターフェースにメンバを追加するだけで、TypeScriptはその追加を認識します。これらのインターフェースをlib.d.tsに関連付けるには、これらの変更を グローバルモジュール で行う必要があることに注意してください。このために、 global.d.ts という特別なファイルを作成することをお勧めします。

ここでは、 windowMathDateに要素を追加する例をいくつか示します:

windowの例

単にWindowインターフェースにものを追加します:

interface Window {
    helloWorld(): void;
}

これにより、あなたはそれを安全な方法で使うことができます:

// Add it at runtime
window.helloWorld = () => console.log('hello world');
// Call it
window.helloWorld();
// Misuse it and you get an error:
window.helloWorld('gracius'); // Error: Supplied parameters do not match the signature of the call target

Mathの例

グローバル変数Mathlib.d.tsで定義されています(再度、あなたの開発ツールを使って定義に移動してください):

/** An intrinsic object that provides basic mathematics functionality and constants. */
declare var Math: Math;

すなわち、変数MathMathインターフェースのインスタンスです。Mathインターフェースは次のように定義されています:

interface Math {
    E: number;
    LN10: number;
    // others ...
}

つまり、グローバル変数のMathに物を追加したいのであれば、それをグローバルインターフェースのMathに追加するだけです。seedrandomプロジェクト を参考に、グローバルMathオブジェクトにseedrandom関数を追加してください。これは非常に簡単に宣言できます:

interface Math {
    seedrandom(seed?: string);
}

これで、それを使うことができます:

Math.seedrandom();
// または
Math.seedrandom("何らかの文字列");

Dateの例

lib.d.tsDate変数の定義を見ると、次のようになっています:

declare var Date: DateConstructor;

DateConstructorというインターフェースは、Dateグローバル変数を使って使うことができるメンバが含まれている点で、MathWindowで見たものに似ています。 例えばDate.now()です。これらのメンバに加えて、Dateインスタンス(例えばnew Date())を作成するためのコンストラクタのシグネチャが含まれています。 DateConstructorインターフェースの断片を以下に示します:

interface DateConstructor {
    new (): Date;
    // ... その他の構成シグネチャ

    now(): number;
    // ... その他のメンバー関数
}

datejs というプロジェクトを例にして考えてみましょう。 DateJSは、メンバをDateグローバル変数とDateインスタンスの両方に追加します。したがって、このライブラリのTypeScriptの定義は、以下のようになります(ところで、コミュニティはすでにそれをあなたのために書いています):

/** DateJS Public Static Methods */
interface DateConstructor {
    /** Gets a date that is set to the current date. The time is set to the start of the day (00:00 or 12:00 AM) */
    today(): Date;
    // 続く
}

/** DateJS Public Instance Methods */
interface Date {
    /** Adds the specified number of milliseconds to this instance. */
    addMilliseconds(milliseconds: number): Date;
    // 続く
}

これにより、型安全な方法で次のようなことができます:

var today = Date.today();
var todayAfter1second = today.addMilliseconds(1000);

stringの例

文字列の lib.d.tsを調べると、Date(Stringグローバル変数、StringConstructorインターフェース、Stringインターフェース)のようなものが見つかるでしょう。しかし、注意すべき点の1つは、以下のコードサンプルで示すように、Stringインターフェースは、文字列リテラルに対しても影響がある、という点です:

interface String {
    endsWith(suffix: string): boolean;
}

String.prototype.endsWith = function(suffix: string): boolean {
    var str: string = this;
    return str && str.indexOf(suffix, str.length - suffix.length) !== -1;
}

console.log('foo bar'.endsWith('bas')); // false
console.log('foo bas'.endsWith('bas')); // true

同様の変数とインターフェースは、NumberBooleanRegExpなどの静的メンバとインスタンスメンバの両方を持つ他のものにも存在し、これらのインターフェースはこれらの型のリテラルのインスタンスにも影響します。

string後方一致の例

メンテナンス上の理由から、global.d.tsを作成することを推奨しました。しかし、あなたが望むのであればファイルモジュールの中からグローバルな名前空間に入れることができます。これはdeclare global {/ * global namespace here * /}を使って行います。例えば。前の例は次のようにすることもできます:

// Ensure this is treated as a module.
export {};

declare global {
    interface String {
        endsWith(suffix: string): boolean;
    }
}

String.prototype.endsWith = function(suffix: string): boolean {
    var str: string = this;
    return str && str.indexOf(suffix, str.length - suffix.length) !== -1;
}

console.log('foo bar'.endsWith('bas')); // false
console.log('foo bas'.endsWith('bas')); // true

独自のカスタムlib.d.tsを使用する

前に述べたように、 --noLibのコンパイラフラグを使用すると、TypeScriptは自動的にlib.d.tsを除外します。これが有用である理由はさまざまです。一般的なもののいくつかを以下に示します。

  • 標準ブラウザベースのランタイム環境とは大きく異なるカスタムJavaScript環境で実行する場合

  • コード内で使用可能なグローバルを厳密に制御したい場合。例えばlib.d.tsはitemを大域変数として定義していますが、あなたはそれをコードに混入させたくないでしょう

デフォルトの lib.d.tsを除外すると、コンパイルコンテキストに同様の名前のファイルを含めることができ、TypeScriptは型チェックのためにそれを取り込みます。

注意: --noLibには注意してください。一度noLibを使ったら、あなたのプロジェクトを他の人と共有しようとしたとき、noLibを(またはあなたのLibを)使うことを強制することになります。さらに悪いことに、もし彼らのコードをプロジェクトに持っていこうとすると、あなたのlibに基づくコードに変換する必要があるかもしれません。

コンパイラターゲットのlib.d.tsに対する効果

コンパイラのターゲットを es6に設定するとlib.d.tsPromiseのようなより現代的なもの(es6)のための環境宣言を追加します。コンパイラターゲットがコードの環境を変えるという魔法の効果は、一部の人にとっては望ましいことです。他の人にとっては、コードと環境を合わせないといけないので、問題があります。

しかしそれでも、あなたの環境をきめ細かく制御したい場合は、次に述べる--libオプションを使うべきです。

libオプション

場合によっては、コンパイルターゲット(生成されたJavaScriptのバージョン)と環境ライブラリサポートの関係を切り離したい場合があります。2016年6月において一般的な例は、Promiseです。たいていは--target es5のようにすることを望むと思います。しかし、それでも、Promiseのような最新の機能を使いたい場合、これをサポートするために、libコンパイラオプションを使ってlibを明示的に制御することができます。

注意: --libを使うと、--targetのlibの魔法を切り離して、より細かい制御ができます。

このオプションをコマンドラインまたはtsconfig.jsonに指定することができます(それを推奨します)。

コマンドライン

tsc --target es5 --lib dom,es6

tsconfig.json

"compilerOptions": {
    "lib": ["dom", "es6"]
}

libsは次のように分類できます。

  • JavaScriptのバルク機能:

    • es5

    • es6

    • es2015

    • es7

    • es2016

    • es2017

    • esnext

  • 実行時環境

    • dom

    • dom.iterable

    • webworker

    • scripthost

  • ESNext By-Featureオプション(バルク機能よりも小さい)

    • es2015.core

    • es2015.collection

    • es2015.generator

    • es2015.iterable

    • es2015.promise

    • es2015.proxy

    • es2015.reflect

    • es2015.symbol

    • es2015.symbol.wellknown

    • es2016.array.include

    • es2017.object

    • es2017.sharedmemory

    • esnext.asynciterable

注意: --libオプションは非常に細かく調整された制御を提供します。したがって、たいていは、バルク機能と環境カテゴリから対象を選択すれば良いでしょう。 --libが指定されていない場合、デフォルトのライブラリが選択されます:

  • --target es5の場合 => es5、dom、scripthost

  • --target es6の場合 => es6、dom、dom.iterable、scripthost

私の個人的な推奨:

"compilerOptions": {
    "target": "es5",
    "lib": ["es6", "dom"]
}

ES5にシンボル(Symbol)を含む例:

ターゲットがes5の場合、Symbol APIは含まれません。実際のところ[ts]Cannot find name 'Symbol'ようなエラーが表示されます。 "target": "es5"と "lib"を組み合わせて、TypeScriptにSymbol APIを提供することができます:

"compilerOptions": {
    "target": "es5",
    "lib": ["es5", "dom", "scripthost", "es2015.symbol"]
}

古いJavaScriptエンジン用のポリフィル

この件に関するEgghead PRO Video

Map/Setや、Promise(このリストは当然変更されるでしょう)のような、いくつかのランタイム機能は、モダンなlibオプションで使用できるものがかなりあります。これらを使うには core-jsを使うだけです。単に、インストールしてください:

npm install core-js --save-dev

また、アプリケーションのエントリポイントにインポートを追加します。

import "core-js";

それは、これらのランタイム機能をあなたのためにポリフィルしてくれるでしょう🌹

最終更新