What does 'declare' do in 'export declare class Actions'?

Solution 1:

found what I was looking for:

Declare vs. var

var creates a new variable. declare is used to tell TypeScript that the variable has been created elsewhere. If you use declare, nothing is added to the JavaScript that is generated - it is simply a hint to the compiler.

For example, if you use an external script that defines var externalModule, you would use declare var externalModule to hint to the TypeScript compiler that externalModule has already been set up

Solution 2:

To understand this, you have to first understand the "declare" keyword.

Here is a good explanation from Gil Fink's Blog:

The TypeScript declare keyword is used to declare variables that may not have originated from a TypeScript file.

For example, lets imagine that we have a library called myLibrary that doesn’t have a TypeScript declaration file and have a namespace called myLibrary in the global namespace. If you want to use that library in your TypeScript code, you can use the following code:

declare var myLibrary;

The type that the TypeScript runtime will give to myLibrary variable is the any type. The problem here is that you won’t have Intellisense for that variable in design time but you will be able to use the library in your code. Another option to have the same behavior without using the declare keyword is just using a variable with the any type:

var myLibrary: any;

Both of the code examples will result in the same JavaScript output but the declare example is more readable and expresses an ambient declaration.


So after you understand the "declare" keyword, go back to wherever you find the

export declare class Action{
...
}

The class's real implementation is probably in somewhere else—maybe a .js file.

Solution 3:

declare in typescript:

The declare keyword in typescript is useful for telling the typescript compiler that a declaration is defined somewhere else (somewhere written in an external javascript file or part of the runtime environment).

Let's say we have a variable called foo declared somewhere else. When we then try to reference the variable the typescript compiler will throw an error:

foo = 'random'; // Error: 'foo' is not defined

We can fix this problem using the declare keyword:

declare var foo: string;
foo = 'random';  // no error anymore

This has the following consequences:

  • When foo actually isn't declared anywhere else, and we try to use the variable a runtime error might occur. So only use the declare keyword when you know the variable is available at this point.
  • Because we know the types, we (potentially) get access to our IDE Intellisense.
  • Because we know the types, the typescript compiler can check the types at compile time, and can warn us if we are using the wrong types in certain scenarios.

Solution 4:

The declare keyword in this specific case:

export declare class Actions {
    ...
}

... is apparently useless and I think TypeScript should consider making this an error (I don't know if there's a hidden reason). If you declare a class, you will never need to import it. If you export a class expecting someone to import it, you don't need to declare it. And because you are declaring this class, by definition, this class should be usable without the need to import it. But this is not true when you export declare a class. You need to import it to use.

TL;DR

export declare class Actions {
    ...
}

is the same as

declare class Actions {
    ...
}

Solution 5:

declare - without any import or export keywords - defines declaration files automatically picked by TypeScript, which is an useful feature to add typing to legacy modules (npm installed packages without TypeScript definitions).

import / export is the proper way to use modules, and everything needs to be manually (and I find a bit tediously) imported, either it's logic, either it's definitions.

As a practical use case, export declare allows you to avoid exporting all the sub-elements, e.g.:

export declare namespace Redux {
    namespace Store {
        interface Definition { ... }
    }
}

Which may be easier to read than:

export namespace Redux {
    export namespace Store {
        export interface Definition { ... }
    }
}

The external import is the same in both cases (e.g. import { Redux } from 'definitions/redux';), which I don't know if it's good practice or not, but I find it tidy! ^^

It's important to keep in mind that adding an import or export to your file will promote it to be a module, therefore the declare scope won't be at global level anymore.

PS, there is a bug (issue 16671): if you use const enum in your declaration (I do that for the redux actions type) and you specified the transpileOnly flag (create-react-app-typescript package does, that's why I know), the enum won't be inlined! You may run in it, you may not, but it's useful to know beforehand!