A Type Declaration or Type Definition file is a TypeScript file with a .d.ts
file extension. What is the difference between them and a normal .ts
file? What are their characteristics? Next, let’s take a deeper look.
I. The .d.ts
files
Type declaration files have the suffix .d.ts
and contain only type-related code, not logical code. Their purpose is to provide type information to the developer, so they are only useful during the development phase.
Type declarations, i.e. declarations of types, such as interface
, function
and class
, are shown below as an interface
declaration.
II. Global declarations
global declaration works in any TypeScript project or TypeScript code fragment. For example, when you write const p = new Promise();
, TypeScript compiler will not compile your code, because const p = new Promise();
syntax error, if you are using vscode IDE, then vscode prompt you as in the following figure (personal code, used to use white) background, vscode’s default background color is black, although the theme color is different, but the prompt is the same).
vscode detects your syntax errors based on global declarations. Every TypeScript program can use global declarations without the need to display them imported with the import
statement.
From the IDE prompt, you can see that the Promise
type is defined in the lib.es2015.promise.d.ts
file, provided by TypeScript, which provides many of these declaration files, called Standard Library (these declaration files are installed with TypeScript).
Using the
lib
compiler option, you can control which standard libraries are introduced into the current project. You can also setnoLib
totrue
, which will disable all standard libraries in the project. More on this can be found at Compilation.
In order to manually go through and load some global declaration files, we need to tell the TypeScript compiler where the declaration files are located. This can be set via the typeRoots
and types
compiler options.
Next, get hands-on. Create the following file structure.
In our project, we need some public types that are available in each ts file, so I’m going to store these public type declarations in project/types/common/main.d.ts
, using typeRoots
to tell TypeScript the location of the declaration file. The TypeScript compiler will import the declaration files in the directory specified by typeRoots
according to the Node module location policy, and if the typeRoots
option, the declaration files in the node_modules/@types
folder will be imported by default.
node_modules/@types
is the default for typeRoots
. The purpose of node_modules/@types
is only to provide type declarations for public packages, and each declaration module in the directory should contain an index.d.ts
file in the root directory to be used as the typescirpt If there is no index.d.ts
file, it should have a package.json
file, and the package.json
file needs to point to the location of the entry declaration file.
Now I need to use the project/types/common/main.d.ts
file as the entry declaration file, so I need to add the following to the project/types/common/package.json
file.
typings
is used to indicate the location of the entry declaration file.
Next, configure typeRoots
to tell TypeScript to customize the location of the global declaration by modifying the tsconfig.json
file as follows.
Add the declaration information to the main.d.ts
file.
With the declaration information, you can use the type in program.ts
.
As shown in the image, the ross
variable of type Person
is defined and the IDE reports an error because the assignment is not compatible with the type, and the IDE also gives the location of the declaration file. Modify the program.ts file as follows to fix the error.
III. Declarations Modularity
In the above example, TypeScript only knows the main.d.ts
declaration file. If the project contains thousands of declarations, putting them all in the main.d.ts
file will make the project very bad and unmaintainable. Therefore, declarations need to be modularized.
First add the functions.d.ts
and interfaces.d.ts
files to the project/types/common/
folder.
interfaces.d.ts
provides information about all the interface types in the common
package, and functions.d.ts
provides information about all the function types in the common
package. And introduce them in the main.d.ts
file using the <reference />
directive.
|
|
One thing worth noting is that we can use the Person
interface defined in the interfaces.d.ts
file in the functions.d.ts
file, because with the <reference />
designation, the specified files can share type declarations.
Modify the program.ts
file to use the defined types.
IV. Third-party declarations
So far, it is known how to create custom global declaration files. In some cases, we need to install the npm declaration file package provided by a third party.
The DefinitelyTyped community, they provide us with many third-party npm declaration file packages, such as @types/lodash
and @types/node
and so on. You can use npm to install the declaration packages under @types
.
|
|
These packages are downloaded to the node_modules/@types
folder, which is why the default value for typeRoots
is node_modules/@types
. If you want to add an additional declaration folder directory to the default value, you need to specify two values for typeRoots
.
V. Environment-related declarations
Certain values that exist only at runtime. For example, the window
object, which exists only in the browser environment, and similarly the global
in node globals.html#globals_global).
If you use window
or glbal
in a TypeScript program, the typescirpt compiler reports an error cannot find name 'window'
. This is normal, because the window
variable is not defined. So, how can we use the window
object if it is not defined?
We need to use the declare
keyword to tell the TypeScript compiler that the window
variable exists and to stop reporting errors.
|
|
This code is called ambient declaration, where window
is called ambient value. With this declaration, TypeScript assumes that the window
variable of type any
is already defined, so no errors will be reported anywhere the window
variable is used.
You can also provide a specified type for the environment value, for example declare var window: Person;
Next, add an environment value XiaoMing
to the main.d.ts
file.
Then use it in program.ts
.
|
|
TypeScript does not report an error if it is not written incorrectly.
VI. Namespace declarations
In the previous example, we provided the types/common
declaration package, which defines the global Person
interface type. The global interface type has the disadvantage that it is easily overwritten by the types of declaration files in other packages (type conflict).
To avoid this problem, the best solution is to define the types in namespaces.
Modify the contents of the declaration file as follows.
|
|
Again, only declaration information is allowed in the declaration file, because a namespace is an object, so you can’t define it in the declaration file, but we can define the namespace as an environment value.
Also, when the namespace is defined in the declaration file, the export
keyword is not needed, and all types inside the namespace are implicitly exported. in addition, you cannot export a value from the namespace, only the type is allowed to be exported.
VII. Type Extensions
When typescript foresees multiple interface types with the same name, it automatically merges these interface types into a single declaration.
Namespace has similar behavior. When declaring an existing namespace, typescript will automatically extend the existing namespace. So when interfaces and namespaces are in the global environment, they can be redeclared for the purpose of extending them.
Update the declaration file.
|
|
Update program.ts
.
At this point typescript does not report an error. The Person
interface and the Number
(built-in type) interface have been extended in program.ts
.
However, this does not apply to the module system; values and types can only be shared in script files, which are files that do not contain the import
and export
statements.
You can add a line of code export {}
to the end of the program.ts
file. At this point typescript should give the following error message.
Because adding the export {}
code converts the program.ts
file into a module, in this case typeScript does not extend the type in the global environment, but redeclares the type within the current module.
TypeScript provides a declare global
environment declaration statement, which can be used to add declarations to the global scope within a module.
To update program.ts
, use the declare global
statement.
|
|
This time typescript does not report an error and successfully extends the global type within the module.