What is the simplest possible example of where `declare` keyword is useful in TypeScript?

Your example is correct. For example you are using a node module which is written in plain javascript (no typings available), so the tscompiler will notice that (since it searches for the typings which are usually in the node module or an extra @typings/package).

You can however provide those typings yourself by telling the tscompiler in the tsconfig.json to look at file xyz.d.ts for the typings e.g.

tsconfig.json
{
  "files": [
    "typings/index.d.ts"
  ]
}

The index.d.ts is where all your custom typings are gathered which can look like this

index.d.ts
/// <reference path="custom-typings.d.ts" />

and the custom-typings.d.ts has the actual typings in it. This is where the declare keyword comes into play

custom-typings.d.ts
declare module "the-untyped-node-module-name" {
    export default class TheNodeModuleClass { 
        static showNotification(string: any): void;
    }
}

Now the Typescript Compiler knows there is a TheNodeModuleClass in the-untyped-node-module-name which has the static function showNotification.

For more info See Typscript Modules.


This is one use case for the keyword declare. There are of course more of it like declare var, declare function, declare class and so on.


Murat Karagöz answer above pointed in the right direction, and this answer will provide actual code with the minimal example of where we would use declare.

Here is a very simple npm module: just one index.js file that exports an object with one method on it. There are no type declarations here because it's just JS.

const item = {
    price: 5,
    name: 'item1',
};

export const MyModuleObject = { method: () => item };

Here is a very simple TypeScript npm project, with one dependency: the JS project linked above. The latter is therefore an imported npm module with no typings. Here is the index.ts file in the TS project:

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

import { MyModuleObject } from 'npmModule';

import { LocalModuleObject } from './module';

// Without the "reference path" line, TS complains in line 3 that it could not find a declaration file for 'npmModule'.
// In this case, the import has type any, so TS does not complain about the call below to an inexistent method.
// When we uncomment line 1, we get a TS error on line 8: property 'test' does not exist on type { method: ... }
MyModuleObject.test();


// TS complains that test does not exist on type { method: ... }
// Here we did not need to have a `declare` statement in a type definitions file for TS to know this because here TS is
// using contextual typing:
LocalModuleObject.test();

Below is the code for index.d.ts:

declare module "npmModule" {
    export const Item: {
        price: number,
        name: string
    }

    export const MyModuleObject: {
        method: () => Item
    }
}

And the code for ./module:

export const LocalModuleObject = { method: () => 10 };

How is this an example of why declare is used - I put this in the comments of index.ts, but let me explain it in more words. index.ts is importing an object from an external module (one that is in node_modules), and another object from a local module (./module.js). Both modules are exporting an object with one method called method on it. In index.ts I am calling an inexistent method test on each of these objects.

TS uses contextual typing on the import of the local module, so it knows that test doesn't exist on the object. This does not happen on the import of the object in the external module: this import is imported with type any. Therefore, TS does not complain about the call to the inexistent method test. It does, however, complain that there are no typings for the external module, so this is a hint that implicit any is being used.

We can remedy this latter complaint by defining an index.d.ts that provides typings for the external library. This is where declare module is used: it declares what it is that the module npmModule exports; npmModule is the external import. In index.ts we must add the line /// <reference path="index.d.ts"/> so TS knows where to look for types.

Tags:

Typescript