lib.d.ts
lib.d.ts
lib.d.ts
A special declaration file lib.d.ts
ships with every installation of TypeScript. This file contains the ambient declarations for various common JavaScript constructs present in JavaScript runtimes and the DOM.
This file is automatically included in the compilation context of a TypeScript project.
The objective of this file is to make it easy for you to start writing type checked JavaScript code.
You can exclude this file from the compilation context by specifying the --noLib
compiler command line flag (or "noLib" : true
in tsconfig.json
).
Example Usage
As always let's look at examples of this file being used in action:
This code type checks fine because the toString
function is defined in lib.d.ts
for all JavaScript objects.
If you use the same sample code with the noLib
option you get a type check error:
So now that you understand the importance of lib.d.ts
, what do its contents look like? We examine that next.
lib.d.ts
Inside Look
lib.d.ts
Inside LookThe contents of lib.d.ts
are primarily a bunch of variable declarations e.g. window
, document
, math
and a bunch of similar interface declarations e.g. Window
, Document
, Math
.
The simplest way to read the documentation and type annotations of global stuff is to type in code that you know works e.g. Math.floor
and then F12 (go to definition) using your IDE (VSCode has great support for this).
Let's look at a sample variable declaration, e.g. window
is defined as:
That is just a simple declare var
followed by the variable name (here window
) and an interface for a type annotation (here the Window
interface). These variables generally point to some global interface e.g. here is a small sample of the (actually quite massive) Window
interface:
You can see that there is a lot of type information in these interfaces. In the absence of TypeScript you would need to keep this in your head. Now you can offload that knowledge on the compiler with easy access to it using things like intellisense
.
There is a good reason for using interfaces for these globals. It allows you to add additional properties to these globals without a need to change lib.d.ts
. We will cover this concept next.
Modifying Native Types
Since an interface
in TypeScript is open ended this means that you can just add members to the interfaces declared in lib.d.ts
and TypeScript will pick up on the additions. Note that you need to make these changes in a global module for these interfaces to be associated with lib.d.ts
. We even recommend creating a special file called global.d.ts
for this purpose.
Here are a few example cases where we add stuff to window
, Math
, Date
:
Example window
window
Just add stuff to the Window
interface e.g.:
This will allow you to use it in a type safe manner:
Example Math
Math
The global variable Math
is defined in lib.d.ts
as (again, use your dev tools to navigate to definition):
i.e. the variable Math
is an instance of the Math
interface. The Math
interface is defined as:
This means that if you want to add stuff to the Math
global variable you just need to add it to the Math
global interface, e.g. consider the seedrandom
project which adds a seedrandom
function to the global Math
object. This can be declared quite easily:
And then you can just use it:
Example Date
Date
If you look at the definition of the Date
variable in lib.d.ts
you will find:
The interface DateConstructor
is similar to what you have seen before with Math
and Window
in that it contains members you can use off of the Date
global variable e.g. Date.now()
. In addition to these members it contains construct signatures which allow you to create Date
instances (e.g. new Date()
). A snippet of the DateConstructor
interface is shown below:
Consider the project datejs
. DateJS adds members to both the Date
global variable and Date
instances. Therefore a TypeScript definition for this library would look like (BTW the community has already written this for you in this case):
This allows you to do stuff like the following in a TypeSafe manner:
Example string
string
If you look inside lib.d.ts
for string you will find stuff similar to what we saw for Date
(String
global variable, StringConstructor
interface, String
interface). One thing of note though is that the String
interface also impacts string literals as demonstrated in the below code sample:
Similar variables and interfaces exist for other things that have both static and instance members like Number
, Boolean
, RegExp
, etc. and these interfaces affect literal instances of these types as well.
Example string
redux
string
reduxWe recommended creating a global.d.ts
for maintainability reasons. However, you can break into the global namespace from within a file module if you desire so. This is done using declare global { /*global namespace here*/ }
. E.g. the previous example can also be done as:
Using your own custom lib.d.ts
As we mentioned earlier, using the --noLib
boolean compiler flag causes TypeScript to exclude the automatic inclusion of lib.d.ts
. There are various reasons why this is a useful feature. Here are a few of the common ones:
You are running in a custom JavaScript environment that differs significantly from the standard browser based runtime environment.
You like to have strict control over the globals available in your code. E.g. lib.d.ts defines
item
as a global variable and you don't want this to leak into your code.
Once you have excluded the default lib.d.ts
you can include a similarly named file into your compilation context and TypeScript will pick it up for type checking.
Note: be careful with
--noLib
. Once you are in noLib land, if you choose to share your project with others, they will be forced into noLib land (or rather your lib land). Even worse, if you bring their code into your project you might need to port it to your lib based code.
Compiler target effect on lib.d.ts
lib.d.ts
Setting the compiler target to es6
causes the lib.d.ts
to include additional ambient declarations for more modern (es6) stuff like Promise
. This magical effect of the compiler target changing the ambience of the code is desirable for some people and for others it's problematic as it conflates code generation with code ambience.
However, if you want finer grained control of your environment, you should use the --lib
option which we discuss next.
lib option
Sometimes (many times) you want to decouple the relationship between the compile target (the generated JavaScript version) and the ambient library support. A common example is Promise
, e.g. today (in June 2016) you most likely want to --target es5
but still use the latest features like Promise
. To support this you can take explicit control of lib
using the lib
compiler option.
Note: using
--lib
decouples any lib magic from--target
giving you better control.
You can provide this option on the command line or in tsconfig.json
(recommended):
Command line:
tsconfig.json:
The libs can be categorized as follows:
JavaScript Bulk Feature:
es5
es6
es2015
es7
es2016
es2017
esnext
Runtime Environment
dom
dom.iterable
webworker
scripthost
ESNext By-Feature Options (even smaller than bulk 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
NOTE: the
--lib
option provides extremely fine tuned control. So you most likely want to pick an item from the bulk + environment categories. If --lib is not specified a default library is injected:
For --target es5 => es5, dom, scripthost
For --target es6 => es6, dom, dom.iterable, scripthost
My Personal Recommendation:
Example Including Symbol with ES5:
Symbol API is not included when target is es5. In fact, we receive an error like: [ts] Cannot find name 'Symbol'. We can use "target": "es5" in combination with "lib" to provide Symbol API in TypeScript:
Polyfill for old JavaScript engines
There are quite a few runtime features that are like Map
/ Set
and even Promise
(this list will of course change over time) that you can use with modern lib
options. To use these all you need to do is use core-js
. Simply install:
And add an import to your application entry point:
And it should polyfill these runtime features for you 🌹.
Last updated