declare keyword in TypeScript

declare keyword

1. Introduction

The declare keyword is used to tell the compiler that a certain type exists and can be used in the current file.

Function: It allows the current file to use types declared by other files. For example, if your script uses a function defined by an external library, the compiler will report an error because it does not know the type definition of the external function. In this case, you can use the declare keyword in your script to tell the compiler the type of the external function, and compile it like this. The script will not report an error because of the use of external types.

The declare keyword can describe the type, class, Enum, function, module and namespace declared by the variable, type or interface command.

The most important feature of the declare keyword is that it only informs the compiler that a certain type exists without giving a specific implementation. For example, only describing the type of a function without giving the implementation of the function is impossible without using declare.

declare can only be used to describe existing variables and data structures, and cannot be used to declare new variables and data structures. In addition, all declare statements will not appear in the compiled file.

2. declare variable

Type descriptions of external variables can be given. For example, if the current script uses the global variable x defined by another script, because the current script does not know its type, the compiler will report an error. However, if you use the declare command to give its type, no error will be reported.

x = 123; // Error report
declare let x:number;
x = 1;

If the declare keyword does not give a specific type of the variable, the variable type is any.

If ts does not find the variable given by the declare keyword, it is assumed to be of type any.

The declare keyword is only used to give a type description. It is a pure type code. It is not allowed to set the initial value of a variable and does not involve values, otherwise an error will be reported.

// Error report
declare let x:number = 1;

3. declare function

The declare keyword can give the type of the external function.

declare function sayHello(
  name: string
):void;

sayHello('Zhang San');

Function types cannot be declared separately in ts

// Error report
function sayHello(
  name: string
):void;
function sayHello(name) {<!-- -->
  return 'Hello,' + name;
}

4. declare class

declare can give a description of the class type

declare class Animal {<!-- -->
  constructor(name:string);
  eat():void;
  sleep():void;
}

5. declare module, declare namespace

If you want to organize variables, functions, and classes together, you can use declare with module or namespace.

declare namespace AnimalLib {<!-- -->
  class Animal {<!-- -->
    constructor(name:string);
    eat():void;
    sleep():void;
  }

  type Animals = 'Fish' | 'Dog';
}

// or
declare module AnimalLib {<!-- -->
  class Animal {<!-- -->
    constructor(name:string);
    eat(): void;
    sleep(): void;
  }

  type Animals = 'Fish' | 'Dog';
}

In declare module and declare namespace, you can add or not add the export keyword.

declare namespace Foo {<!-- -->
  export var a: boolean;
}

declare module 'io' {<!-- -->
  export function readFile(filename:string):string;
}

Example: Using external library (myLib)

declare namespace myLib {<!-- -->
  function makeGreeting(s:string): string;
  let numberOfGreetings: number;
}

When properties and methods can be added to external modules, a type description of the new part is given.

Here, the Foo interface is imported from the module moduleA, renamed to Bar, and used the declare keyword as Bar Add an attribute custom

import {<!-- --> Foo as Bar } from 'moduleA';

declare module 'moduleA' {<!-- -->
  interface Bar extends Foo {<!-- -->
    custom: {<!-- -->
      prop1: string;
    }
  }
}

Example: A project has multiple modules. In one module, the interface of another module can be type extended.

Here the script a.ts defines an interface A, and the script b.ts adds the attribute y to this interface . declare module './a' {} means to declare the type of the module in a.ts, and the interface with the same name will be automatically merged, so it is equivalent to the extended type . The essence is to add a new interface with the same name, because it will be automatically merged with the same name.

// a.ts
export interface A {<!-- -->
  x: number;
}

// b.ts
import {<!-- --> A } from './a';

declare module './a' {<!-- -->
  interface A {<!-- -->
    y:number;
  }
}

const a:A = {<!-- --> x: 0, y: 0 };

When using this syntax to extend module types, there are two points to note:

(1) The module name NAME in the declare module NAME syntax is the same as the module name rules for import and export, and must be written in the same way as the statement to load the module in the current file. (The above example import { A } from './a') remains consistent.

(2) New top-level types cannot be created. In other words, only existing types in the a.ts module can be extended, and new top-level types are not allowed to be added, such as defining a new interface B.

(3) The default default interface cannot be expanded, only the named interface output by the export command can be expanded. This is because when performing type expansion, you need to rely on the output interface name.

For some third-party modules, the original author does not provide an interface type. In this case, you can add the following line of commands at the top of your script. After adding the above command, external modules can be compiled even if they have no type declaration. However, all interfaces imported from this module will be of type any.

declare module "module name";

// example
declare module "hot-new-module";

The module name described by declare module can use wildcard characters. The module name my-plugin-* means adapting to all module names starting with my-plugin- (such as my-plugin-logger).

declare module 'my-plugin-*' {<!-- -->
  interface PluginOptions {<!-- -->
    enabled: boolean;
    priority: number;
  }

  function initialize(options: PluginOptions): void;
  export = initialize;
}

6. declare global

If you want to add properties and methods to native js objects, you can use the declare global{} syntax. You can only extend the type description of an existing object, not add a new top-level type.

Here, the toSmallString() method is added to the js native String object and the type description of this new method is given.

The empty export statement export {} in the first line forces the compiler to treat this script as a module. This is because declare global must be used inside the module.

export {<!-- -->};
declare global {<!-- -->
  interface String {<!-- -->
    toSmallString(): string;
  }
}
String.prototype.toSmallString = ():string => {<!-- -->
  // Implementation
  return '';
};

7. declare enum

Enum type description can be given

declare enum E1 {<!-- -->
  A,
  B,
}
declare enum E2 {<!-- -->
  A = 0,
  B = 1,
}
declare const enum E3 {<!-- -->
  A,
  B,
}
declare const enum E4 {<!-- -->
  A = 0,
  B = 1,
}

8. declare module is used for type declaration files

You can define a .d.ts file for each module script, and put all the type definitions used by the script in this file. However, a more convenient approach is to define a large .d.ts file for the entire project, and use declare module in this file to define the type of each module script.

Definition

Here url and path are separate module scripts, and their types are defined in the node.d.ts file.

// node.d.ts
declare module "url" {<!-- -->
  export interface Url {<!-- -->
    protocol?: string;
    hostname?: string;
    pathname?: string;
  }
  export function parse(
    urlStr: string,
    parseQueryString?,
    slashesDenoteHost?
  ): Url;
}
declare module "path" {<!-- -->
  export function normalize(p: string): string;
  export function join(...paths: any[]): string;
  export var sep: string;
}
Use

When using it, use the triple slash command in your own script to load this type declaration file.

/// <reference path="node.d.ts"/>

Without the above line of command, when your script uses an external module, you need to use the declare command in the script to specify the type of the external module separately.