diff --git a/website/_data/guides.yml b/website/_data/guides.yml index f020ebb8fc2..13e12bf18be 100644 --- a/website/_data/guides.yml +++ b/website/_data/guides.yml @@ -103,6 +103,14 @@ - path: "/docs/libdefs/" # - path: "/docs/libdefs/usage/" - path: "/docs/libdefs/creation/" + additional_reading: + - guide: declarations + +- id: declarations + pages: + - path: "/docs/declarations/" + additional_reading: + - guide: libdefs # - id: errors # pages: diff --git a/website/_data/i18n/en.yml b/website/_data/i18n/en.yml index 7184f9f72bd..2d75f86bddb 100644 --- a/website/_data/i18n/en.yml +++ b/website/_data/i18n/en.yml @@ -218,6 +218,9 @@ docs_additional_reading: "Additional Reading" "/docs/libdefs/usage/": title: "Using Library Definitions" description: "" +"/docs/declarations/": + title: "Declaration Files" + description: ".js.flow" "/docs/modules/": title: "Modules" description: "" @@ -426,6 +429,10 @@ guides: description: > Learn how to create and use library definitions for the third-party code your code depends on. + declarations: + title: "Declaration Files" + description: > + Learn how to write and publish types alongside your NPM package. # errors: # title: "Debugging Errors" # description: > diff --git a/website/en/docs/declarations/index.md b/website/en/docs/declarations/index.md new file mode 100644 index 00000000000..692f1c153af --- /dev/null +++ b/website/en/docs/declarations/index.md @@ -0,0 +1,87 @@ +--- +layout: guide +--- + +## What's a "Declaration File"? + +Let's look at a more general, and sometimes more convenient, way to +declare types for modules: `.js.flow` files. + +The exported types of a module may be declared in a _declaration file_ with +the `.js.flow` extension, colocated with the corresponding _implementation +file_ with the `.js` extension. + +A declaration file for a module shadows a +colocated implementation file for that module when typechecking other code +that may depend on that module. + + +For example, suppose we have the following code in a file `src/LookBeforeYouLeap.js`: + +```js +// @flow +import { isLeapYear } from "./Misc"; +if (isLeapYear("2020")) console.log("Yay!"); +``` + +Next, suppose that `src/Misc.js` had an incompatible implementation of +`isLeapYear`, just as above. + +```js +// @flow +export function isLeapYear(year: number): boolean { + return year % 4 == 0; // yeah, this is approximate +} +``` + +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](../libdefs/creation). + +```js +// @flow +declare export function isLeapYear(year: string): boolean; +``` + +What do you think will happen? + +Right, the `isLeapYear` call in `src/LookBeforeYouLeap.js` will typecheck. +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. +That said, declaration files provide a very convenient way to write +specifications for modular typechecking. Sometimes, the implementation code +may not yet be free of type errors, but we may want to move on and come back +to fixing the type errors later. Another important use of this feature is for +libraries, whose implementation code may be too complex to typecheck +satisfactorily, but whose clients we still want to typecheck against +well-defined specifications. + +## Inlining declarations in regular code + +As noted above, declarations should be distinct from regular code. But +sometimes, it is useful to do declarations "inline," as part of the source of +an implementation file. + +**Proceed with caution!** + +The most common use is writing "work-in-progress" code while ensuring that +your code typechecks. 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. Easy! (Just don't forget to replace the +declarations with proper implementations.) + +```js +declare class List { + map(f: (x: T) => U): List; +} +declare function foo(n: number): string; + +function fooList(ns: List): List { + return ns.map(foo); +} +``` diff --git a/website/en/docs/libdefs/creation.md b/website/en/docs/libdefs/creation.md index 42e559b605a..0fb77d80a69 100644 --- a/website/en/docs/libdefs/creation.md +++ b/website/en/docs/libdefs/creation.md @@ -89,8 +89,7 @@ declare module "some-third-party-library" { The name specified in quotes after `declare module` can be any string, but it should correspond to the same string you'd use to `require` or `import` the third-party module into your project. For defining modules that are accessed via -a relative `require`/`import` path, please see the docs on the `.js.flow` files -which will be available soon. +a relative `require`/`import` path, please see the docs on the [`.js.flow` files](../declarations) Within the body of a `declare module` block, you can specify the set of exports for that module. However, before we start talking about exports we have to talk