Understand all aspects of TypeScript type declarations

.d.ts Type declaration/definition file is an important part of TypeScript. I hope this article can help you understand the following issues:

  • How are type declarations recognized by TypeScript?
  • How to use the type declaration file of a third-party package?
  • How does TypeScript code compile and generate a type declaration file?
  • How to write a type declaration file for a third-party package, and how to correct type errors in a third-party package

Type declaration file

There are two main file types in TypeScript: .ts and .d.ts. Files with the suffix .d.ts are called The type declaration file for TypeScript is mainly used to describe the type information of all exported interfaces in the module (the declaration file only defines the type for type checking, not code implementation, and cannot be assigned).

How type declarations are referenced

1.TypeScript built-in type declaration

When you install TypeScript, it comes with a lot of type declarations: lib. The es5.full.d.ts declaration file contains various common environment declarations in the JavaScript runtime and DOM.

img

Take the DOM type as an example:

const aEle = document.querySelector('a') // HTMLAnchorElement | null
const canvasEle = document.querySelector('#my_canvas') as HTMLCanvasElement

We look for the a tag, and TypeScript can automatically infer that the type is HTMLAnchorElement | null.

If TypeScript cannot infer the specific element type through element ID search, we can use type assertions to explicitly specify the element type as HTMLCanvasElement (For assertion content, you can read: Understanding type assertions and usage in TypeScript Scenes). When variables have clear types, we can also wait for better type checking and syntax hints.

The HTMLAnchorElement and HTMLCanvasElement mentioned above are TypeScript’s built-in DOM type declarations, that is, Quotation content, for specific content, please refer to: dom.generated.d.ts.

2. Type declarations that come with third-party packages

Some third-party packages will come with their own type declaration files, through "types" or "typings" in the package.json file. Field to specify the declaration file location, taking vue as an example:

{
  "name": "vue",
  "typings": "types/index.d.ts",
  "exports": {
    ".": {
      "import": {
        "node": "./dist/vue.runtime.mjs",
        "default": "./dist/vue.runtime.esm.js"
      },
      "require": "./dist/vue.runtime.common.js",
      "types": "./types/index.d.ts"
    },
    "./dist/*": "./dist/*",
    "./types/*": "./types/*",
    "./package.json": "./package.json"
  },
  "scripts": {
    "build:types": "rimraf temp & amp; & amp; tsc --declaration --emitDeclarationOnly --outDir temp & amp; & amp; api-extractor run & amp; & amp; api-extractor run - c packages/compiler-sfc/api-extractor.json",
    "test:types": "npm run build:types & amp; & amp; tsc -p ./types/tsconfig.json",
    "format": "prettier --write --parser typescript "(src|test|packages|types)/**/*.ts"",
    "ts-check": "tsc -p tsconfig.json --noEmit",
    "ts-check:test": "tsc -p test/tsconfig.json --noEmit",
  }
}

vue is written using TypeScript. Use the tsc command in npm scripts build:types to generate the type definition file to the temporary folder temp:

tsc --declaration --emitDeclarationOnly --outDir temp

And process and merge multiple .d.ts in temp through api-extractor.

Note: package.json uses types and typings to specify type declaration files, not type, type is used to specify the file module scheme, usually module or commonjs (default).

3. Statement file maintained by the community

The third-party packages used in some projects may not be written in TypeScript. There is no way to directly compile the code to generate the .d.ts declaration file, and there is no type declaration file maintained in the package. We can TypeScript community find solutions.

Definitely Typed is a declaration class library maintained by the community. For some projects that are not written in TypeScript, we can find the type declarations we want, which greatly simplifies the difficulty of migrating JS projects to TS. The installed @types/xxx packages are maintained in Definitely Typed.

For example, @types/react can be found in DefinitelyTyped.

By default, @types/react and @types/react-dom installed in the project will be automatically introduced by the compiler, and TypeScript will search upwards from the current directory for all The packages in node_modules/@types include directories such as ./node_modules/@types and ../node_modules/@types.

However, if a specified directory is configured through typeRoots in tsconfig.json, the type declaration module in that directory will be automatically introduced.

{
  "compilerOptions": {
    "typeRoots": ["./typings", "node_modules/@types"]
  }
}

Note: The default value of typeRoots is “node_modules/@types”. If you specify another directory, it will not be searched from the default directory. If you still want to use the installed “@types/xxx”, you need to add the default value.

How to confirm whether the third party used contains a type definition file?

There will be a corresponding tag on NPM, written in TypeScript, and the TS logo will be displayed:
image.png

The type definition maintained in DefinitelyTyped will be displayed with the DT logo:

image.png

How to generate type definition files for projects written in TypeScript

In projects developed using TypeScript, you can use tsc to compile and generate type declaration files, and configure the compilation options in tsconfig.json:

// tsconfig.json
{
    "compilerOptions": {
        "declaration": true, // Used to specify whether to generate the corresponding *.d.ts file after compilation is completed
        "emitDeclarationOnly": true // Only the declaration file will be generated, not the js file.
    }
}

Parameters can also be specified via the command line:

tsc --declaration --emitDeclarationOnly

Like vue introduced above, specify the type through the "types" or "typings" field in package.json Just declare the file.

Specify compilation scope

There are two ways to specify the file to be compiled:

  • Use the files attribute
  • Use the include and exclude attributes

If neither files nor include is set, the compiler will include all TS files in the path by default except for files excluded by exclude .

If both files and include are set, the compiler will include the files specified by both.

If exclude is not set, its default value is node_modules, bower_components, jspm_packages and the compile option outDir The path specified.

exclude is only valid for include, not for files. That is, if the file specified by files is also excluded by exclude, the file will still be introduced by the compiler.

As mentioned earlier, any dependencies of files imported by files or include will be automatically imported.

Write .d.t for JS or third-party code

When using TypeScript, you may encounter the following problems:

  • I use a library written in JS. I don’t want to rewrite it in TypeScript, so I add .d.ts to it.
  • The third-party library used in the project does not have a type declaration file
  • The third-party library lacks some types or incorrectly defines some types and needs to be supplemented and corrected.
1. Import and export type definitions

If you want to define all types related to a certain module in one file, you can create a .ts file and use export to export it. In other files, you can directly use import reference.

2. Supplementary third-party package types

Some libraries do not provide type declarations, or the declared types do not match the actual API. We can also supplement them in declare.

declare can be used to declare global variables, functions, classes, or enhanced module types:

  • Declare module: When using a third-party library, you can use the declare keyword to declare the module type. This can avoid TypeScript errors and allow for better type checking. and autocomplete.
// global.d.ts
declare module 'my-library-a';

In the above code, we declare my-library-a, but without any type definition, the private any type will be obtained. When using third-party packages, TypeScript always prompts for type errors or missing type definitions, and you don’t want to write types, so you can use this method.

If we only use certain methods of the third-party library, or some types of the third-party library have errors, we can use declare to supplement the types.

// global.d.ts
declare module 'my-library-b' {<!-- -->
    export function myFunction(): void;
    export const myVariable: string;
}
  • Declare global variables, functions, objects:
// global.d.ts
declare const A: string;
declare function B(): void;
declare interface User {<!-- -->
    name: string;
    age: number;
}
3. Generate .d.ts tool

Microsoft also provides a tool for writing declaration files for third-party libraries: dts-gen. Using dts-gen, you can generate TypeScript definition files (.d.ts) from any JavaScript object.

If you want to write type declarations for the JS code you write or the NPM modules introduced in the project, you can use dts-gen, which will perform type inference and automatically generate .d.ts files.

Finally, to make the written type declaration file (.d.ts) effective and used in the project, you need to add it to the of the tsconfig.json file. include or files.

{<!-- -->
"compilerOptions": {<!-- -->
// Other configuration items...
},
"include": [
"src/**/*.ts",
"typings/*.d.ts" // Assume your type declaration file is in the typings folder
]
}

In the above example, we add typings/*.d.ts to the include array to ensure that the TypeScript compiler will include the typings file All .d.ts files in the folder.

tsconfig.json configuration reuse

We can use extends to implement configuration reuse, that is, one configuration file can inherit the configuration properties of another file.

For example, create a basic configuration file configs/base.json:

{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true
  }
}

Then, tsconfig.json can reference the configuration of this file:

{
  "extends": "./configs/base",
  "files": [
    "main.ts",
    "supplemental.ts"
  ]
}

This kind of inheritance has two characteristics:

  • Configurations with the same name in the inheritor will overwrite the inherited one
  • All relative paths are resolved to the path of the file they are located in
Reference documentation

Understanding Typescript configuration files

Definitely Typed

Welcome to follow the public account “Chaos Front End”