lib.d.ts

Last updated 2 months ago

lib.d.ts

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

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

  • このファイルの目的は型チェックのある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が存在しない場合、あなたの頭にこれを保持する必要があります。コンパイルの知識を、インテリセンス(Intellisense)のようなものを使って容易にアクセスできるようにすることができます。

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

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

TypeScriptのinterfaceはオープンエンドなので、lib.d.tsで宣言されたインターフェースにメンバーを追加するだけで、TypeScriptはその追加を認識します。これらのインタフェースをlib.d.tsに関連付けるには、これらの変更を グローバルモジュール で行う必要があることに注意してください。このために、 globals.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();
// or
Math.seedrandom("Any string you want!");

Dateの例

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

declare var Date: DateConstructor;

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

interface DateConstructor {
new (): Date;
// ... other construct signatures
now(): number;
// ... other member functions
}

プロジェクト 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;
// ... so on and so forth
}
/** DateJS Public Instance Methods */
interface Date {
/** Adds the specified number of milliseconds to this instance. */
addMilliseconds(milliseconds: number): Date;
// ... so on and so forth
}

これにより、タイプセーフな方法で次のようなことができます:

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

    • スクリプトホスト

  • 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エンジン用のPolyfill

この件に関するEgghead PRO Video

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

npm install core-js --save-dev

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

import "core-js";

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