Declaration Files
What's a Declaration File?
Let's look at a more general, and sometimes more convenient way to
declare types for modules: .flow
files.
There are two possible use cases, depending on whether an implementation file exists or not.
In the first case, the exported types of a module are declared in a declaration
file <FILENAME>.flow
, that is located in the same directory as the corresponding implementation
file <FILENAME>
. The declaration file completely shadows the colocated
implementation. In other words, Flow will completely ignore <FILENAME>
and just
read <FILENAME>.flow
instead.
In the second case, the implementation file is missing entirely. <FILENAME>.flow
is treated as if it is named <FILENAME>
.
Note that the .flow
extension applies both to .js
files as well as .json
ones. The corresponding declaration files have extensions .js.flow
and .json.flow
,
respectively.
Now let's see an example of the first case documented above. Suppose we have the
following code in a file src/LookBeforeYouLeap.js
:
import { isLeapYear } from "./Misc";
if (isLeapYear("2020")) console.log("Yay!");
and suppose that src/Misc.js
has an incompatible implementation of isLeapYear
:
1export function isLeapYear(year: number): boolean {2 return year % 4 == 0; // yeah, this is approximate3}
If we now create a declaration file src/Misc.js.flow
, the declarations in it
will be used instead of the code in src/Misc.js
. Let's say we have the
following declarations in src/Misc.js.flow
.
NOTE: The syntax for declarations in a declaration file is the same as we've seen in Creating Library Definitions section.
1declare export function isLeapYear(year: string): boolean;
What do you think will happen?
Right, the isLeapYear
call in src/LookBeforeYouLeap.js
will typecheck, since
the year
parameter expects a string
in the declaration file.
As this example shows, declaration files must be written with care: it is up to the programmer to ensure they are correct, otherwise they may hide type errors.
Inlining declarations in regular code
Sometimes it is useful to make declarations inline, as part of the source of an implementation file.
In the following example, say you want to finish writing
the function fooList
without bothering to mock up its dependencies first: a
function foo
that takes a number
and returns a string
, and a class
List
that has a map
method. You can do this by including declarations for
List
and foo
:
1declare class List<T> {2 map<U>(f: (x: T) => U): List<U>;3}4declare function foo(n: number): string;5
6function fooList(ns: List<number>): List<string> {7 return ns.map(foo);8}
Just don't forget to replace the declarations with proper implementations.