lib

Selects which built-in type declarations are loaded, independently of target.

Signature
"lib": string[]  // e.g. ["ES2023", "DOM", "DOM.Iterable"]
  • Added in TypeScript 2.0

Parameters

ParameterTypeDescription
$ES5optionalstringCore definitions for all ES5 functionality.
$ES2015 (alias ES6)optionalstringAdds array.find, Promise, Proxy, Symbol, Map, Set, Reflect and friends.
$ES2016 … ES2022optionalstringYear-by-year additions: array.include (2016); Object.entries/values (2017); async iterables and promise.finally (2018); array.flat and Object.fromEntries (2019); string.matchAll (2020); promise.any and string.replaceAll (2021); array.at and RegExp.hasIndices (2022).
$ES2023optionalstringAdds array.with, array.findLast, array.findLastIndex, array.toSorted and array.toReversed.
$ESNextoptionalstringThe newest proposed APIs. Its contents shift between TypeScript releases, so pinning a year is safer for libraries.
$DOMoptionalstringBrowser globals: window, document, fetch, Element and the rest.
$DOM.IterableoptionalstringIterator signatures for DOM collections such as NodeList and FormData. Folded into DOM and left as an empty file in TypeScript 6.0.
$WebWorkeroptionalstringThe global scope available inside a Web Worker or service worker.
$ScriptHostoptionalstringAPIs for the Windows Script Hosting System.
$Granular componentsoptionalstringIndividual pieces such as ES2015.Core, ES2015.Collection, ES2015.Promise, ES2017.Object and ES2021.WeakRef, for partially polyfilled runtimes.

Return value

Replaces the default set of built-in .d.ts declaration files loaded into the program.

Errors

Errors with TS6046 when a name is not a known library file. Referencing an API from a library you did not include is a normal type error, such as "Property 'toSorted' does not exist on type 'number[]'".

Changelog

  • PHP 4.5lib files can be overridden by npm packages such as @typescript/lib-dom, so a project can pin its own DOM declarations.
  • PHP 6.0Added es2025 as a lib value (RegExp.escape, Promise.try, Iterator and Set methods). The contents of dom.iterable and dom.asynciterable moved into dom, leaving those two names as empty files. libReplacement now defaults to false.

lib controls which built-in declaration files describe the runtime you are compiling for. It answers a question target cannot: which APIs exist, as opposed to which syntax is emitted.

Why the two differ

Left alone, lib is derived from target — target: es2017 gives you ES2017 APIs plus the DOM. That coupling breaks in two common situations. A server project has no window or document, yet the DOM globals are loaded by default, so a typo like name silently resolves to window.name instead of erroring. And a project that ships polyfills has APIs available that its conservative target knows nothing about.

How to set it

Naming lib replaces the default set outright; it does not add to it. So a Node project usually writes something like ["ES2023"] — deliberately dropping DOM — while a browser project writes ["ES2023", "DOM", "DOM.Iterable"]. Entries are case-insensitive and combine freely, and granular names such as ES2015.Promise let you admit exactly the one API your polyfill provides.

What trips people up

A generous lib makes the checker believe an API exists; it does not put it in the runtime. Listing ES2023 while shipping to a browser that lacks Array.prototype.toSorted compiles cleanly and throws at runtime.

Example

Example · typescript
// tsconfig.json
//   { "compilerOptions": { "target": "es2017", "lib": ["ES2023"] } }
// target stays at ES2017 for emit; lib admits the ES2023 APIs a polyfill provides.
// Note: no "DOM" in the list, so `document` and `window` do not type check.

const scores: number[] = [3, 1, 2];

const sorted = scores.toSorted();               // ES2023
const last = scores.findLast((n) => n < 3);     // ES2023

console.log(sorted, last, scores);
// -> [ 1, 2, 3 ] 2 [ 3, 1, 2 ]  (toSorted does not mutate)

When to use it

  • Removing DOM globals from a Node.js or CLI project so browser-only APIs fail to compile.
  • Declaring polyfilled APIs such as Object.fromEntries while keeping a lower target for emit.
  • Typing a service worker or Web Worker bundle with WebWorker instead of DOM.
  • Pinning a year like ES2023 instead of ESNext so a TypeScript upgrade cannot move the goalposts.

Frequently asked questions

What is the difference between lib and target in tsconfig?

target controls which JavaScript syntax is emitted and downlevelled, while lib controls which built-in API declarations are loaded for type checking. target sets the default for lib, but you can set lib separately when polyfills give you newer APIs than your emit level.

How do I remove DOM types from a Node project?

Set lib explicitly without "DOM", for example "lib": ["ES2023"], because lib replaces the default set rather than adding to it. Browser globals such as document, window, name and fetch then stop type checking.

Why does toSorted or findLast not exist on my array?

Those are ES2023 APIs, so "ES2023" (or a later year, or ESNext) must appear in lib, either directly or via target. Adding it only satisfies the type checker — the runtime still needs the method or a polyfill.

More examples

Dropping DOM catches a class of silent bugs

The DOM library injects globals like name, length, status, origin and event into every scope. On a server those names are never defined at runtime, so leaving DOM in the lib list turns typos into values typed string instead of compile errors.

Example · typescript
// tsconfig.json (server): { "lib": ["ES2023"] }

function describe(user: { first: string; last: string }) {
  // With "DOM" loaded, a bare `name` resolves to the global window.name,
  // typed string, and this compiles: no error, always "".
  // With DOM removed it is error TS2304: Cannot find name 'name'.
  const name = `${user.first} ${user.last}`;
  return name;
}

console.log(describe({ first: "Ada", last: "Lovelace" }));
// -> Ada Lovelace

Granular entries for a partially polyfilled runtime

Naming individual library components admits exactly the APIs the polyfill provides and no more. Proxy stays undeclared, so reaching for it is a compile error rather than a runtime crash on the old browsers this build targets.

Example · typescript
// tsconfig.json
// { "compilerOptions": {
//     "target": "es5",
//     "lib": ["ES5", "ES2015.Promise", "ES2015.Collection", "DOM"]
// } }
// The runtime has a Promise and Map polyfill, but no Proxy or Symbol.

const seen = new Map<string, number>();
seen.set("a", 1);

const ready: Promise<number> = Promise.resolve(seen.get("a") ?? 0);
const value = await ready;

console.log(value, seen.size);
// -> 1 1

// const p = new Proxy({}, {}); // error TS2304: Cannot find name 'Proxy'

Discussion

  • Be the first to comment on this lesson.