Supporting lib from node_modules
TL;DR
DOMの型定義 lib.dom.d.ts
を差し替えできるようになった。
lib.dom.d.tsとは何ぞ?
DOM APIの型定義が書いてあるファイル。
setTimeout
window
fetch
イメージ的には「グローバルに生えているAPIの型定義」に近い。
setTimeout(() => {
window.alert("");
fetch("https://foo.com");
}, 1000);
// setTimeout,window,fetchなどこのファイルで型定義されている。
declare function setTimeout(...): number;
interface Window extends ... {
alert(message?: any): void;
...
}
interface WindowOrWorkerGlobalScope {
fetch(...): Promise<Response>;
}
lib.dom.d.tsはどこにある?
TypeScriptをインストールした時に一緒にくっついてくる。 node_modulesフォルダを覗くとファイルとして存在している。
"dependencies": {
"typescript": "4.1.5",
}
node_modulesフォルダにはlib.dom.d.tsの他に「lib.es2015.object.d.ts」や「lib.es2015.promise.d.ts」などの「d.ts」ファイルが存在している。
これらはtsconfig.jsonの lib
指定で「どのファイルを読み込むか」を指定できる。
// tsconfig.json
"lib": ["dom", "es2015"]
// node_modules/@typescriptのこれらが読み込まれる
lib.dom.d.ts
lib.es2015.object.d.ts
lib.es2015.promise.d.ts
// tsconfig.json
"lib": ["dom", "es2020"]
// node_modules/@typescriptのこれらが読み込まれる
lib.dom.d.ts
lib.es2020.object.d.ts
lib.es2020.promise.d.ts
es2015
や es2020
はECMAScriptのバージョンを示している。
ECMA2020で新しいAPIが追加されるとTypeScriptが es2020
のファイル群を追加し、そこに新しいAPIの型定義が書かれる。
例えばECMA2022で追加された Object.hasOwn
というAPIがある。
lib.es2022.object.d.tsを見ると、hasOwnの型定義が追加されたことが分かる。
https://github.com/microsoft/TypeScript/blob/main/lib/lib.es2022.object.d.ts
// lib.es2022.object.d.ts
interface ObjectConstructor {
...
hasOwn(o: object, v: PropertyKey): boolean;
}
lib:["es2022"]
を指定すればlib.es2022.object.d.tsが読み込まれ Object.hasOwn
の型が解決できる。それ以前の lib:["es2015"]
など指定している場合、TypeScriptは Object.hasOwn
の型を見つけられず型定義エラーになる。
ここで、もう一度node_modulesフォルダの下を覗いてみよう。
lib.dom.d.ts
lib.es2015.object.d.ts
lib.es2015.promise.d.ts
lib.es2015.iterable.d.ts
lib.es2022.object.d.ts
lib.es2022.promise.d.ts
...
dom
にはバージョン番号がなく、ひとつのファイルしか存在しない。
「グローバルに生えているAPI」を定義したlib.dom.d.tsはどこでECMAScriptのバージョン指定ができるのか?
グローバルに生えた新しいAPIが使えない?
そういえば最近 structuredClone
を使いたかったけど型の未定義エラーになってしまったので、これを追いかけてみる。

"lib.dom.d.ts" v4.1.5
structuredClone
を使って Cannot find name
エラーになったv4.1.5。グローバルっぽいオブジェクトを探しても、確かに定義されていない。
"lib.dom.d.ts" v4.7.4
structuredClone
があった。
TypeScriptそのものをアップデート(従来)
TypeScript v4.7に structuredClone
が存在するなら、そのバージョンをインストールすればいいことになる。
npm install typescript@4.7
// lib.dom.tsがv4.7にアップデートされる
// ここにはstructuredCloneが定義されている
実際には、フレームワークだったり他のパッケージとの兼ね合いでそんなに気軽にTypeScriptのバージョンは上げられない。ほんの一部分の要求のために、プロジェクトすべてに影響する解決策をとるのはリスクが高い。
lib.dom.d.tsをアップデート(新)
TypeScript v4.5から TypeScriptのバージョンを上げずにlib.dom.d.tsだけ差し替える ことができるようになった。
オフィシャルでメンテナンスされている「@types/web」パッケージをインストールすることで任意のlib.dom.d.tsをプロジェクトに取り込むことができる。
https://www.npmjs.com/package/@types/web
「@types/web」の2022/10時点の最新リリースはv0.0.75だった。
https://github.com/microsoft/TypeScript-DOM-lib-generator/releases/tag/%40types%2Fweb%400.0.75
ソースを追いかけると...。あった structuredClone
が入っている。
という訳で「@types/web」のv0.0.75をインストール。
"dependencies": {
"@typescript/lib-dom": "npm:@types/web@0.0.75"
}
グローバルに生えた新しいAPIが使えるようになった
structuredClone
の型定義が見つかるようになり、コンパイルエラーは出なくなった。

2つのlib.dom.d.ts
TypeScriptに同梱されたlib.dom.d.tsと「@types/web」に同梱されたlib.dom.d.ts。 ローカルのプロジェクトには2つのlib.dom.d.tsが存在する。
// node_modules/@typescript
lib.dom.d.ts
lib.es2015.object.d.ts
lib.es2015.string.d.ts
lib.es2020.object.d.ts
lib.es2020.string.d.ts
...
// node_modules/@types/web
lib.dom.d.ts
「@types/web」が存在する場合、このフォルダのlib.dom.d.tsが読み込まれる。 これが今回のアップデート「Supporting lib from node_modules」で追加された機能になる。
Last updated