# Flow > Upgrading to [Types-First](../../lang/types-first) mode may require a substantial --- --- title: Flow Annotate-Exports slug: /cli/annotate-exports --- Upgrading to [Types-First](../../lang/types-first) mode may require a substantial number of type annotations at module boundaries. To help with the process of upgrading large codebases, we are providing a codemod command, whose goal is to fill in these missing annotations. This command is included in the Flow binary in versions `>= 0.125`. > Note: As of version 0.134, types-first is the default mode. If you are using a version `>=0.134`, make sure you set `types_first=false` in your .flowconfig while running this codemod. This command uses types that Flow infers, to fill in positions that would otherwise raise *signature-verification* failures. It will include the necessary type import statements, as long as the respective types are exported from their defining modules. It is designed for use on multiple files at once, rather than one file at a time. For this reason it doesn't connect to an existing Flow server, but rather starts a checking process of its own. As is typical with such mechanized approaches, it comes with a few caveats: 1. It won’t be able to fill in every required type annotation. Some cases will require manual effort. 2. Inserted annotations may cause new flow errors, since it’s not always possible to match inferred type with types that can be written as annotations. 3. File formatting may be affected. If a code formatter (e.g. prettier) is used, it is recommended that you run it after the codemod has finished running. ### How to apply the codemod {#toc-how-to-apply-the-codemod} A typical way to invoke this command is ``` flow codemod annotate-exports \ --write \ --repeat \ --log-level info \ /path/to/folder \ 2> out.log ``` This command will transform files under `/path/to/folder`. This does not need to be the root directory (the one containing `.flowconfig`). It uses the following flags: * `--write` will update files that require annotations under `/path/to/folder` in-place. Without this flag the resulting files will be printed on the command line. * `--repeat` ensures that the transformation will be applied until no more files change. This mode is necessary here, because each new type the codemod adds may require new locations to be annotated. * `--log-level info` outputs useful debugging information in the standard error stream. This option might lead to verbose output, so we're redirecting the error output to a log file `out.log`. Another convenient way to provide the input is by passing the flag ``` --input-file file.txt ``` where `file.txt` contains a specific list of files to be transformed. ### Codemod output {#toc-codemod-output} After each iteration of the codemod, a summary will be printed on the CLI. This summary includes statistical information about the number of annotations that were added, and how many locations were skipped. It also prints counts for various kinds of errors that were encountered. These can be matched to the errors printed in the logs. A common error case is when a type `A`, defined in a file `a.js`, but not exported, is inferred in file `b.js`. The codemod will skip adding this annotation and report an error in the logs. The fix this case, you can export `A` in `a.js`. Note that it is not necessary to manually import `A` in `b.js`. The codemod will do this automatically. --- --- title: Flow Coverage slug: /cli/coverage --- The coverage command provides a metric of the amount of checking that Flow has performed on each part of your code. A program with high Flow coverage should increase your confidence that Flow has detected any potential runtime errors. The determining factor for this is the presence of [`any`](../../types/any/) in the inferred type of each expression. An expression whose inferred type is `any` is considered *uncovered*, otherwise it is considered *covered*. To see why this metric was chosen for determining Flow's effectiveness, consider the example ```js flow-check const one: any = 1; one(); ``` This code leads to a runtime type error, since we are attempting to perform a call on a number. Flow, however, does not flag an error here, because we have annotated variable `one` as `any`. Flow's checking is effectively turned off whenever `any` is involved, so it will silently allow the call. The use of this *unsafe* type has rendered the type checker ineffective, and the coverage metric is here to surface this, by reporting all instances of `one` as uncovered. ## Design Space {#toc-design-space} **Which types should be "covered"?** What was described above is a rather coarse grained way to determine coverage. One could imagine a criterion that flags expressions as uncovered if *any* part of their type includes `any`, for example `Array`. While there is value in a metric like this, the "uncovered" part of the type will typically be uncovered through various operations on values of this type. For example, in the code ```js flow-check declare const arr: Array; arr.forEach(x => {}); ``` the parameter `x` will be flagged as uncovered. Also, in practice, a strict criterion like this would be too noisy and rather expensive to compute on the fly. **Union types** An exception to this principle are union types: the type `number | any` is considered *uncovered*, even though technically `any` is not the top-level constructor. Unions merely encode an option among *a set of* other types. In that sense we are conservatively viewing an expression as uncovered, when at least one possible type of that expression causes limited checking. For example, in the code ```js flow-check let x: number | any = 1; x = "a"; ``` Flow will let you assign anything to `x`, which reduces confidence in the use of `x` as a number. Thus `x` is considered uncovered. **The empty type** An interesting type from a coverage perspective is the [`empty`](../../types/empty) type. This type roughly corresponds to *dead code*. As such checking around expressions with type `empty` is more relaxed, but for a good reason: this code will not be executed at runtime. Since it is a common practice to clean up such code, Flow coverage will also report code whose type is inferred to be `empty`, but distinguishes it from the case of `any`. ## Command Line Use {#toc-command-line-use} To find out the coverage of a file foo.js with the following contents ```js flow-check function add(one: any, two: any): number { return one + two; } add(1, 2); ``` you can issue the following command ``` $ flow coverage file.js Covered: 50.00% (5 of 10 expressions) ``` This output means that 5 out of the 10 nodes of this program were inferred to have type `any`. To see exactly which parts are uncovered you can also pass one of the following flags: * `--color`: This will print foo.js on the terminal with the uncovered locations in red color. E.g. `flow coverage --color file.js` * `--json`: This will list out all location spans that are uncovered under the tag `"uncovered_locs"`. E.g. `flow coverage --json file.js` Finally, as an example of dead code, consider the code: ```js flow-check function f(x: 'a' | 'b') { if (x === 'a') { // ... } else if (x === 'b') { // ... } else { x; } } ``` The final `else` clause should never be reached, as we've already checked for both members of the union. Because of this, `x` is inferred to have the type `empty` in that branch. In the colored version of this command, these parts appear in blue color, and in the JSON version they are under the field `"empty_locs"`. **Use on multiple files** If you want to check coverage of multiple files at once, Flow offers the `batch-coverage` command: ``` $ flow batch-coverage dir/ ``` will report coverage statistics for each file under `dir/`, as well as aggregate results. Note that `batch-coverage` requires a non-lazy Flow server. --- --- title: Flow CLI slug: /cli description: How to use Flow from the command line. Including how to manage the Flow background process. --- The flow command line tool is made to be easy-to-use for simple cases. Using the command `flow` will type-check your current directory if the `.flowconfig` file is present. A flow server will automatically be started if needed. The CLI tool also provides several other options and commands that allow you to control the server and build tools that integrate with Flow. For example, this is how the [Nuclide](https://nuclide.io/) editor integrates with Flow to provide autocompletion, type errors, etc. in its UI. To find out more about the CLI just type: ```sh flow --help ``` This will give you information about everything that flow can do. Running this command should print something like this: ``` Usage: flow [COMMAND] [PROJECT_ROOT] Valid values for COMMAND: ast Print the AST autocomplete Queries autocompletion information batch-coverage Shows aggregate coverage information for a group of files or directories check Does a full Flow check and prints the results check-contents Run typechecker on contents from stdin config Read or write the .flowconfig file coverage Shows coverage information for a given file cycle Output .dot file for cycle containing the given file find-module Resolves a module reference to a file find-refs Gets the reference locations of a variable or property force-recheck Forces the server to recheck a given list of files get-def Gets the definition location of a variable or property graph Outputs dependency graphs of flow repositories init Initializes a directory to be used as a flow root directory ls Lists files visible to Flow lsp Acts as a server for the Language Server Protocol over stdin/stdout [experimental] print-signature Prints the type signature of a file as extracted in types-first mode server Runs a Flow server in the foreground start Starts a Flow server status (default) Shows current Flow errors by asking the Flow server stop Stops a Flow server type-at-pos Shows the type at a given file and position version Print version information Default values if unspecified: COMMAND status PROJECT_ROOT current folder Status command options: --color Display terminal output in color. never, always, auto (default: auto) --from Specify client (for use by editor plugins) --help This list of options --json Output results in JSON format --no-auto-start If the server is not running, do not start it; just exit --old-output-format Use old output format (absolute file names, line and column numbers) --one-line Escapes newlines so that each error prints on one line --quiet Suppresses the server-status information that would have been printed to stderr --retries Set the number of retries. (default: 3) --show-all-errors Print all errors (the default is to truncate after 50 errors) --strip-root Print paths without the root --temp-dir Directory in which to store temp files (default: /tmp/flow/) --timeout Maximum time to wait, in seconds --version Print version number and exit ``` Example with custom project root: ```sh mydir ├── frontend │ ├── .flowconfig │ └── app.js └── backend ``` ```sh flow check frontend ``` You can then, further dig into particular COMMANDs by adding the `--help` flag. So, for example, if you want to know more about how the autocomplete works, you can use this command: ```sh flow autocomplete --help ``` --- --- title: .flowconfig [declarations] slug: /config/declarations --- Often third-party libraries have broken type definitions or have type definitions only compatible with a certain version of Flow. In those cases it may be useful to use type information from the third-party libraries without typechecking their contents. The `[declarations]` section in a `.flowconfig` file tells Flow to parse files matching the specified regular expressions in _declaration mode_. In declaration mode the code is not typechecked. However, the signatures of functions, classes, etc are extracted and used by the typechecker when checking other code. Conceptually one can think of declaration mode as if Flow still typechecks the files but acts as if there is a `$FlowFixMe` comment on every line. See also [`[untyped]`](../untyped) for not typechecking files, and instead using `any` for all contents. Things to keep in mind: 1. Declaration mode should only be used for existing third-party code. You should never use this for code under your control. 2. These are [OCaml regular expressions](http://caml.inria.fr/pub/docs/manual-ocaml/libref/Str.html#TYPEregexp). 3. These regular expressions match against absolute paths. They probably should start with `.*` An example `[declarations]` section might look like: ``` [declarations] .*/third_party/.* .*/src/\(foo\|bar\)/.* .*\.decl\.js ``` This `[declarations]` section will parse in declaration mode: 1. Any file or directory under a directory named `third_party` 2. Any file or directory under `.*/src/foo` or under `.*/src/bar` 3. Any file that ends with the extension `.decl.js` You may use the `` placeholder in your regular expressions. At runtime, Flow will treat the placeholder as if it were the absolute path to the project's root directory. This is useful for writing regular expressions that are relative rather than absolute. For example, you can write: ``` [declarations] /third_party/.* ``` Which would parse in declaration mode any file or directory under the directory named `third_party/` within the project root. However, unlike the previous example's `.*/third_party/.*`, it would NOT parse files or directories under directories named `third_party/`, like `src/third_party/`. --- --- title: .flowconfig [ignore] slug: /config/ignore --- The `[ignore]` section in a `.flowconfig` file tells Flow to ignore files matching the specified regular expressions when type checking your code. By default, nothing is ignored. Things to keep in mind: 1. These are [OCaml regular expressions](http://caml.inria.fr/pub/docs/manual-ocaml/libref/Str.html#TYPEregexp). 2. These regular expressions match against absolute paths. They probably should start with `.*` 3. Ignores are processed AFTER includes. If you both include and ignore a file it will be ignored. An example `[ignore]` section might look like: ``` [ignore] .*/__tests__/.* .*/src/\(foo\|bar\)/.* .*\.ignore\.js ``` This `[ignore]` section will ignore: 1. Any file or directory under a directory named `__tests__` 2. Any file or directory under `.*/src/foo` or under `.*/src/bar` 3. Any file that ends with the extension `.ignore.js` You may use the `` placeholder in your regular expressions. At runtime, Flow will treat the placeholder as if it were the absolute path to the project's root directory. This is useful for writing regular expressions that are relative rather than absolute. For example, you can write: ``` [ignore] /__tests__/.* ``` Which would ignore any file or directory under the directory named `__tests__/` within the project root. However, unlike the previous example's `.*/__tests__/.*`, it would NOT ignore files or directories under other directories named `__tests__/`, like `src/__tests__/`. ### Exclusions {#toc-ignore-exclusions} Sometimes you may want to ignore all files inside a directory with the exception of a few. An optional prefix "!" which negates the pattern may help. With this, any matching file excluded by a previous pattern will become included again. ``` [ignore] /node_modules/.* !/node_modules/not-ignored-package-A/.* !/node_modules/not-ignored-package-B/.* ``` --- --- title: .flowconfig [include] slug: /config/include --- The `[include]` section in a `.flowconfig` file tells Flow to include the specified files or directories. Including a directory recursively includes all the files under that directory. Symlinks are followed as long as they lead to a file or directory that is also included. Each line in the include section is a path to include. These paths can be relative to the root directory or absolute, and support both single and double star wildcards. The project root directory (where your `.flowconfig` lives) is automatically included. For example, if `/path/to/root/.flowconfig` contains the following `[include]` section: ``` [include] ../externalFile.js ../externalDir/ ../otherProject/*.js ../otherProject/**/coolStuff/ ``` Then when Flow checks the project in `/path/to/root`, it will read and watch 1. `/path/to/root/` (automatically included) 2. `/path/to/externalFile.js` 3. `/path/to/externalDir/` 4. Any file in `/path/to/otherProject/` that ends in `.js` 5. Any directory under `/path/to/otherProject` named `coolStuff/` --- --- title: .flowconfig slug: /config description: Flow tries to work out of the box as much as possible, but can be configured to work with any codebase. --- Every Flow project contains a `.flowconfig` file. You can configure Flow by modifying `.flowconfig`. New projects or projects that are starting to use Flow can generate a default `.flowconfig` by running `flow init`. ### `.flowconfig` format {#toc-flowconfig-format} The `.flowconfig` uses a custom format that vaguely resembles INI files. The `.flowconfig` consists of different sections: * [`[version]`](./version) * [`[options]`](./options) * [`[include]`](./include) * [`[ignore]`](./ignore) * [`[untyped]`](./untyped) * [`[declarations]`](./declarations) * [`[libs]`](./libs) * [`[lints]`](./lints) * [`[strict]`](../strict/#toc-enabling-flow-strict-in-a-flowconfig) ### Comments {#toc-comments} Lines beginning with zero or more spaces followed by an `#` or `;` or `💩` are ignored. For example: ``` # This is a comment # This is a comment ; This is a comment ; This is a comment 💩 This is a comment 💩 This is a comment ``` ### Where to put the `.flowconfig` {#toc-where-to-put-the-flowconfig} The location of the `.flowconfig` is significant. Flow treats the directory that contains the `.flowconfig` as the _project root_. By default Flow includes all the source code under the project root. The paths in the [[include] section](./include) are relative to the project root. Some other configuration also lets you reference the project root via the macro ``. Most people put the `.flowconfig` in the root of their project (i.e. next to the `package.json`). Some people put all their code in a `src/` directory and therefore put the `.flowconfig` at `src/.flowconfig`. ### Example {#toc-example} Say you have the following directory structure, with your `.flowconfig` in `mydir`: ```text otherdir └── src ├── othercode.js mydir ├── .flowconfig ├── build │ ├── first.js │ └── shim.js ├── lib │ └── flow ├── node_modules │ └── es6-shim └── src ├── first.js └── shim.js ``` Here is an example of how you could use the `.flowconfig` directives. ```text [include] ../otherdir/src [ignore] .*/build/.* [libs] ./lib ``` Now `flow` will include a directory outside the `.flowconfig` path in its check, ignore the `build` directory and use the declarations in `lib`. --- --- title: .flowconfig [libs] slug: /config/libs --- The `[libs]` section in a `.flowconfig` file tells Flow to include the specified [library definitions](../../libdefs/) when type checking your code. Multiple libraries can be specified. By default, the `flow-typed` folder in your project root directory is included as a library directory. This default allows you to use [`flow-typed`](https://github.com/flowtype/flow-typed) to install library definitions without additional configuration. Each line in the `[libs]` section is a path to the library file or directory which you would like to include. These paths can be relative to the project root directory or absolute. Including a directory recursively includes all the files under that directory as library files. --- --- title: .flowconfig [lints] slug: /config/lints --- The `[lints]` section in a `.flowconfig` file can contain several key-value pairs of the form: ``` [lints] ruleA=severityA ruleB=severityB ``` Check out the [linting docs](../../linting) for more information. --- --- title: .flowconfig [options] slug: /config/options --- import {SinceVersion, UntilVersion} from '../../components/VersionTags'; The `[options]` section in a `.flowconfig` file can contain several key-value pairs of the form: ``` [options] keyA=valueA keyB=valueB ``` Any options that are omitted will use their default values. Some options can be overridden with command line flags. ## Available options {#toc-available-options} ### all {#toc-all} Type: `boolean` Set this to `true` to check all files, not just those with `@flow`. The default value for `all` is `false`. ### autoimports {#toc-autoimports} Type: `boolean` When enabled, IDE autocomplete suggests the exports of other files, and the necessary `import` statements are automatically inserted. A "quick fix" code action is also provided on undefined variables that suggests matching imports. The default value for `autoimports` is `true` as of Flow v0.155.0. ### babel_loose_array_spread {#toc-babel-loose-array-spread} Type: `boolean` Set this to `true` to check that array spread syntax is only used with arrays, not arbitrary iterables (such as `Map` or `Set`). This is useful if you transform your code with Babel in [loose mode](https://babeljs.io/docs/en/babel-plugin-transform-spread#loose) which makes this non-spec-compliant assumption at runtime. For example: ```js const set = new Set(); const values = [...set]; // Valid ES2015, but Set is not compatible with ReadonlyArray in Babel loose mode ``` The default value for `babel_loose_array_spread` is `false`. ### emoji {#toc-emoji} Type: `boolean` Set this to `true` to add emoji to the status messages that Flow outputs when it's busy checking your project. The default value for `emoji` is `false`. ### enums {#toc-enums} Type: `boolean` Set this to `true` to enable [Flow Enums](../../enums). [Additional steps](../../enums/enabling-enums/) are required beyond just enabling the `.flowconfig` option. The default value for `enums` is `false`. ### exact_by_default {#toc-exact-by-default} Type: `boolean` When set to `true` (the default as of version 0.202), Flow interprets object types as exact by default: ```js flow-check type O1 = {foo: number}; // exact type O2 = {|foo: number|}; // exact type O3 = {foo: number, ...}; // inexact ``` When this flag is `false`, Flow has the following behavior: ```js flow-check type O1 = {foo: number}; // inexact type O2 = {|foo: number|}; // exact type O3 = {foo: number, ...}; // inexact ``` - From inception to Flow version 0.199, the default value of the flag was `false`. - In versions 0.200 and 0.201, the flag was required to be explicitly set to either `true` or `false`. - From version 0.202, the default value is `true`. You can read more about this change in our blog post about making [exact by object types by default, by default](https://medium.com/flow-type/exact-object-types-by-default-by-default-cc559af6f69). ### experimental.const_params {#toc-experimental-const-params} Type: `boolean` Setting this to `true` makes Flow treat all function parameters as const bindings. Reassigning a param is an error which lets Flow be less conservative with refinements. The default value is `false`. ### include_warnings {#toc-include-warnings} Type: `boolean` Setting this to `true` makes Flow commands include warnings in the error output. Warnings are hidden by default in the CLI to avoid console spew. (An IDE is a much better interface to show warnings.) The default value is `false`. ### lazy_mode {#toc-lazy-mode} Type: `boolean` For more on lazy modes, see the [lazy modes docs](../../lang/lazy-modes/). Setting `lazy_mode` in the `.flowconfig` will cause new Flow servers for that root to use lazy mode (or no lazy mode if set to `false`). This option can be overridden from the CLI using the `--lazy-mode` flag. The default value is `false`. ### max_header_tokens {#toc-max-header-tokens} Type: `integer` Flow tries to avoid parsing non-flow files. This means Flow needs to start lexing a file to see if it has `@flow` or `@noflow` in it. This option lets you configure how much of the file Flow lexes before it decides there is no relevant docblock. - Neither `@flow` nor `@noflow` - Parse this file with Flow syntax disallowed and do not typecheck it. - `@flow` - Parse this file with Flow syntax allowed and typecheck it. - `@noflow` - Parse this file with Flow syntax allowed and do not typecheck it. This is meant as an escape hatch to suppress Flow in a file without having to delete all the Flow-specific syntax. The default value of `max_header_tokens` is 10. ### module.file_ext {#toc-module-file-ext} By default, Flow will look for files with the extensions `.js`, `.jsx`, `.mjs`, `.cjs` and `.json`. You can override this behavior with this option. For example, if you do: ``` [options] module.file_ext=.foo module.file_ext=.bar ``` Then Flow will instead look for the file extensions `.foo` and `.bar`. > **Note:** you can specify `module.file_ext` multiple times ### module.ignore_non_literal_requires {#toc-module-ignore-non-literal-requires} Type: `boolean` Set this to `true` and Flow will no longer complain when you use `require()` with something other than a string literal. The default value is `false`. ### module.name_mapper {#toc-module-name-mapper} Type: `regex -> string` Specify a regular expression to match against module names, and a replacement pattern, separated by a `->`. For example: ``` module.name_mapper='^image![a-zA-Z0-9$_]+$' -> 'ImageStub' ``` This makes Flow treat `require('image!foo.jpg')` as if it were `require('ImageStub')`. These are [OCaml regular expressions](http://caml.inria.fr/pub/docs/manual-ocaml/libref/Str.html#TYPEregexp). Use `\(` and `\)` (slashes required!) to create a capturing group, which you can refer to in the replacement pattern as `\1` (up to `\9`). > **Note:** you can specify `module.name_mapper` multiple times ### module.name_mapper.extension {#toc-module-name-mapper-extension} Type: `string -> string` Specify a file extension to match, and a replacement module name, separated by a `->`. > **Note:** This is just shorthand for > `module.name_mapper='^\(.*\)\.EXTENSION$' -> 'TEMPLATE'`) For example: ``` module.name_mapper.extension='css' -> '/CSSFlowStub.js.flow' ``` Makes Flow treat `require('foo.css')` as if it were `require(PROJECT_ROOT + '/CSSFlowStub')`. > **Note:** You can specify `module.name_mapper.extension` multiple times for > different extensions. ### module.system {#toc-module-system} Type: `node | haste` The module system to use to resolve `import` and `require`. Haste mode is used by Meta. The default is `node`. ### module.system.node.main_field {#toc-module-system-node-main-field} Type: `string` Flow reads `package.json` files for the `"name"` and `"main"` fields to figure out the name of the module and which file should be used to provide that module. So if Flow sees this in the `.flowconfig`: ``` [options] module.system.node.main_field=foo module.system.node.main_field=bar module.system.node.main_field=baz ``` and then it comes across a `package.json` with ``` { "name": "kittens", "main": "main.js", "bar": "bar.js", "baz": "baz.js" } ``` Flow will use `bar.js` to provide the `"kittens"` module. If this option is unspecified, Flow will always use the `"main"` field. See [this GitHub issue for the original motivation](https://github.com/facebook/flow/issues/5725) ### module.system.node.resolve_dirname {#toc-module-system-node-resolve-dirname} Type: `string` By default, Flow will look in directories named `node_modules` for node modules. You can configure this behavior with this option. For example, if you do: ``` [options] module.system.node.resolve_dirname=node_modules module.system.node.resolve_dirname=custom_node_modules ``` Then Flow will look in directories named `node_modules` or `custom_node_modules`. > **Note:** you can specify `module.system.node.resolve_dirname` multiple times ### module.use_strict {#toc-module-use-strict} Type: `boolean` Set this to `true` if you use a transpiler that adds `"use strict";` to the top of every module. The default value is `false`. ### munge_underscores {#toc-munge-underscores} Type: `boolean` Set this to `true` to have Flow treat underscore-prefixed class properties and methods as private. This should be used in conjunction with [`jstransform`'s ES6 class transform](https://github.com/facebook/jstransform/blob/master/visitors/es6-class-visitors.js), which enforces the same privacy at runtime. The default value is `false`. ### no_flowlib {#toc-no-flowlib} Type: `boolean` Flow has builtin library definitions. Setting this to `true` will tell Flow to ignore the builtin library definitions. The default value is `false`. ### react.runtime {#toc-react-runtime} Type: `automatic | classic` Set this to `automatic` if you are using React's automatic runtime in `@babel/plugin-transform-react-jsx`. Otherwise, use `classic`. [See the babel documentation](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx) for details about the transform. The default value is `classic`. ### server.max_workers {#toc-server-max-workers} Type: `integer` The maximum number of workers the Flow server can start. By default, the server will use all available cores. ### sharedmemory.hash_table_pow {#toc-sharedmemory-hash-table-pow} Type: `unsigned integer` The 3 largest parts of the shared memory are a dependency table, a hash table, and a heap. While the heap grows and shrinks, the two tables are allocated in full. This option lets you change the size of the hash table. Setting this option to X means the table will support up to 2^X elements, which is 16\*2^X bytes. By default, this is set to 19 (Table size is 2^19, which is 8 megabytes) ### sharedmemory.heap_size {#toc-sharedmemory-heap-size} Type: `unsigned integer` This option configures the maximum possible size for the shared heap. You should most likely not need to configure this, as it doesn't really affect how much RSS Flow uses. However, if you are working on a massive codebase you might see the following error after init: "Heap init size is too close to max heap size; GC will never get triggered!" In this case, you may need to increase the size of the heap. By default, this is set to 26843545600 (25 \* 2^30 bytes, which is 25GiB) ### relay_integration {#toc-relay-integration} Type: `boolean` This option enables Flow's [Relay](https://relay.dev) integration. With the integration enabled Flow will infer the types of `graphql` tagged template literals as being the types that the Relay compiler emitted for that fragment/mutaiton/query/etc. This allows users to omit type parameters from common Relay APIs like `useFragment` and `usePreloadedQuery`. ### relay_integration.excludes {#toc-relay-integration-excludes} Type: `string` This option allows you to exclude some directories in the project from using Flow's Relay integration. For example ``` relay_integration=true relay_integration.excludes=/dirA relay_integration.excludes=/dirB ``` ### suppress_type {#toc-suppress-type} Type: `string` This option lets you alias `any` with a given string. This is useful for explaining why you're using `any`. For example, let's say you sometimes want to sometimes use `any` to suppress an error and sometimes to mark a TODO. Your code might look like ``` const myString: any = 1 + 1; const myBoolean: any = 1 + 1; ``` If you add the following to your configuration: ``` [options] suppress_type=$FlowFixMe suppress_type=$FlowTODO ``` You can update your code to the more readable: ``` const myString: $FlowFixMe = 1 + 1; const myBoolean: $FlowTODO = 1 + 1; ``` > **Note:** You can specify `suppress_type` multiple times. You can achieve the same effect by adding the following to your global library definition: ``` type $FlowTODO = any; ``` ### traces {#toc-traces} Type: `integer` Enables traces on all error output (showing additional details about the flow of types through the system), to the depth specified. This can be very expensive, so is disabled by default. ### use_unknown_in_catch_variables {#toc-use-unknown-in-catch-variables} This config was first introduced as `use_mixed_in_catch_variables` and renamed after . Type: `boolean` Changes the default type of `catch` variables from [`any`](../../types/any) to [`unknown`](../../types/unknown). E.g. ```js flow-check try { } catch (e) {} ``` in the above example, if the option is `true`, `catch` will be typed as `unknown` as it lacks an explicit type annotation. ## Deprecated options The following options no longer exist in the latest version of Flow: ### esproposal.class_instance_fields {#toc-esproposal-class-instance-fields} Type: `enable | ignore | warn` Set this to `warn` to indicate that Flow should give a warning on use of instance [class fields](https://github.com/tc39/proposal-class-public-fields) per the pending spec. You may also set this to `ignore` to indicate that Flow should simply ignore the syntax (i.e. Flow will not use this syntax to indicate the presence of a property on instances of the class). The default value of this option is `enable`, which allows use of this proposed syntax. ### esproposal.class_static_fields {#toc-esproposal-class-static-fields} Type: `enable | ignore | warn` Set this to `warn` to indicate that Flow should give a warning on use of static [class fields](https://github.com/tc39/proposal-class-public-fields) per the pending spec. You may also set this to `ignore` to indicate that Flow should simply ignore the syntax (i.e. Flow will not use this syntax to indicate the presence of a static property on the class). The default value of this option is `enable`, which allows use of this proposed syntax. ### esproposal.decorators {#toc-esproposal-decorators} Type: `ignore | warn` Set this to `ignore` to indicate that Flow should ignore decorators. The default value of this option is `warn`, which gives a warning on use since this proposal is still very early-stage. ### esproposal.export_star_as {#toc-esproposal-export-star-as} Type: `enable | ignore | warn` Set this to `enable` to indicate that Flow should support the `export * as` syntax from [leebyron's proposal](https://github.com/leebyron/ecmascript-more-export-from). You may also set this to `ignore` to indicate that Flow should simply ignore the syntax. The default value of this option is `warn`, which gives a warning on use since this proposal is still very early-stage. ### esproposal.optional_chaining {#toc-esproposal-optional-chaining} Type: `enable | ignore | warn` Set this to `enable` to indicate that Flow should support the use of [optional chaining](https://github.com/tc39/proposal-optional-chaining) per the pending spec. You may also set this to `ignore` to indicate that Flow should simply ignore the syntax. The default value of this option is `warn`, which gives a warning on use since this proposal is still very early-stage. ### esproposal.nullish_coalescing {#toc-esproposal-nullish-coalescing} Type: `enable | ignore | warn` Set this to `enable` to indicate that Flow should support the use of [nullish coalescing](https://github.com/tc39/proposal-nullish-coalescing) per the pending spec. You may also set this to `ignore` to indicate that Flow should simply ignore the syntax. The default value of this option is `warn`, which gives a warning on use since this proposal is still very early-stage. ### inference_mode {#toc-inference-mode} Type: `classic | constrain-writes` Setting this to `constrain-writes` will enable the constrained-writes inference mode. For more info, see the [variable declaration docs](../../lang/variables). The default value is `classic` ### log.file {#toc-log-file} Type: `string` The path to the log file (defaults to `/tmp/flow/.log`). ### sharedmemory.dirs {#toc-sharedmemory-dirs} Type: `string` This affects Linux only. Flow's shared memory lives in a memory mapped file. On more modern versions of Linux (3.17+), there is a system call `memfd_create` which allows Flow to create the file anonymously and only in memory. However, in older kernels, Flow needs to create a file on the file system. Ideally this file lives on a memory-backed tmpfs. This option lets you decide where that file is created. By default this option is set to `/dev/shm` and `/tmp` > **Note:** You can specify `sharedmemory.dirs` multiple times. ### sharedmemory.minimum_available {#toc-sharedmemory-minimum-available} Type: `unsigned integer` This affects Linux only. As explained in the [`sharedmemory.dirs`](#toc-sharedmemory-dirs-string) option's description, Flow needs to create a file on a filesystem for older kernels. `sharedmemory.dirs` specifies a list of locations where the shared memory file can be created. For each location, Flow will check to make sure the filesystem has enough space for the shared memory file. If Flow will likely run out of space, it skips that location and tries the next. This option lets you configure the minimum amount of space needed on a filesystem for shared memory. By default it is 536870912 (2^29 bytes, which is half a gigabyte). ### strip_root {#toc-strip-root} Type: `boolean` Obsolete. Set this to `true` to always strip the root directory from file paths in error messages when using `--json`, `--from emacs`, and `--from vim`. Do not use this option. Instead, pass the command line flag `--strip-root`. By default this is `false`. ### suppress_comment {#toc-suppress-comment} Type: `regex` Defines a magical comment that suppresses any Flow errors on the following line. For example: ``` suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe ``` will match a comment like this: ``` // $FlowFixMe: suppressing this error until we can refactor var x : string = 123; ``` and suppress the error. If there is no error on the next line (the suppression is unnecessary), an "Unused suppression" warning will be shown instead. If no suppression comments are specified in your config, Flow will apply one default: `// $FlowFixMe`. > **Note:** You can specify `suppress_comment` multiple times. If you do define > any `suppress_comment`s, the built-in `$FlowFixMe` suppression will be erased > in favor of the regexps you specify. If you wish to use `$FlowFixMe` with some > additional custom suppression comments, you must manually specify > `\\(.\\|\n\\)*\\$FlowFixMe` in your custom list of suppressions. > **Note:** In version v0.127.0, the option to specify the suppression comment > syntax was removed. `$FlowFixMe`, `$FlowIssue`, `$FlowExpectedError`, and > `$FlowIgnore` became the only standard suppressions. ### temp_dir {#toc-temp-dir} Type: `string` Tell Flow which directory to use as a temp directory. Can be overridden with the command line flag `--temp-dir`. The default value is `/tmp/flow`. ### types_first {#toc-types-first} Type: `boolean` For more on types-first mode, see the [types-first docs](../../lang/types-first/). Flow builds intermediate artifacts to represent signatures of modules as they are checked. If this option is set to `false`, then these artifacts are built using inferred type information. If this option is set to `true`, then they are built using type annotations at module boundaries. The default value for `types_first` is `true` (as of version 0.134). ### well_formed_exports {#toc-well-formed-exports} Type: `boolean` Enforce the following restrictions on file exports: - Statements manipulating `module.exports` and the `exports` alias may only appear as top-level statements. - Parts of the source that are visible from a file's exports need to be annotated unless their type can be trivially inferred (e.g. the exported expression is a numeric literal). This is a requirement for types-first mode to function properly. Failure to properly annotate exports raise `signature-verification-failure`s. This option is set to `true` by default, since it is implied by [`types_first`](#toc-types-first-boolean), but the option is useful on its own when upgrading a project from classic mode to types-first mode. ### well_formed_exports.includes {#toc-well-formed-exports-includes} Type: `string` Limit the scope of the `well_formed_exports` requirement to a specific directory of this project. For example ``` well_formed_exports=true well_formed_exports.includes=/dirA well_formed_exports.includes=/dirB ``` will only report export related errors in files under `dirA` and `dirB`. This option requires `well_formed_exports` to be set to `true`. The purpose of this option is to help prepare a codebase for Flow types-first mode. Between versions v0.125.0 and v0.127.0, this option was named `well_formed_exports.whitelist`. --- --- title: .flowconfig [untyped] slug: /config/untyped --- The `[untyped]` section in a `.flowconfig` file tells Flow to not typecheck files matching the specified regular expressions and instead throw away types and treat modules as [`any`](../../types/any). This is different from the [`[ignore]`](../ignore) config section that causes matching files to be ignored by the module resolver, which inherently makes them un-typechecked, and also unresolvable by `import` or `require`. When ignored, [`[libs]`](../libs) must then be specified for each `import` using `flow-typed`, which may not always be desired. It is also different from the [`[declarations]`](../declarations) section. This also does not typecheck the file contents, but `[declarations]` does extract and use the signatures of functions, classes, etc, when checking other code. `[untyped]` instead causes a file to be ignored by the typechecker as if it had `@noflow` in it, resolve modules as `any` type, but allow them to NOT be ignored by the module resolver. Any matching file is skipped by Flow (not even parsed, like other `@noflow` files!), but can still be `require()`'d. Things to keep in mind: 1. These are [OCaml regular expressions](http://caml.inria.fr/pub/docs/manual-ocaml/libref/Str.html#TYPEregexp). 2. These regular expressions match against absolute paths. They probably should start with `.*` An example `[untyped]` section might look like: ``` [untyped] .*/third_party/.* .*/src/\(foo\|bar\)/.* .*\.untyped\.js ``` This `[untyped]` section will parse: 1. Any file or directory under a directory named `third_party` 2. Any file or directory under `.*/src/foo` or under `.*/src/bar` 3. Any file that ends with the extension `.untyped.js` You may use the `` placeholder in your regular expressions. At runtime, Flow will treat the placeholder as if it were the absolute path to the project's root directory. This is useful for writing regular expressions that are relative rather than absolute. For example, you can write: ``` [untyped] /third_party/.* ``` Which would parse in declaration mode any file or directory under the directory named `third_party/` within the project root. However, unlike the previous example's `.*/third_party/.*`, it would NOT parse files or directories under directories named `third_party/`, like `src/third_party/`. --- --- title: .flowconfig [version] slug: /config/version --- You can specify in the `.flowconfig` which version of Flow you expect to use. You do this with the `[version]` section. If this section is omitted or left blank, then any version is allowed. If a version is specified and not matched, then Flow will immediately error and exit. So if you have the following in your `.flowconfig`: ``` [version] 0.22.0 ``` and you try to use Flow v0.21.0, then Flow will immediately error with the message `"Wrong version of Flow. The config specifies version 0.22.0 but this is version 0.21.0"` So far, we support the following ways to specify supported versions - Explicit versions, (e.g. `0.22.0`, which only matches `0.22.0`). - Intersection ranges, which are ANDed together, (e.g. `>=0.13.0 <0.14.0`, which matches `0.13.0` and `0.13.5` but not `0.14.0`). - Caret ranges, which allow changes that do not modify the left-most non-zero digit (e.g. `^0.13.0` expands into `>=0.13.0 <0.14.0`, and `^0.13.1` expands into `>=0.13.1 <0.14.0`, whereas `^1.2.3` expands into `>=1.2.3 <2.0.0`). --- --- title: Declaration Files slug: /declarations description: Learn how to write types in .flow files. --- ## What's a Declaration File? {#toc-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_ `.flow`, that is located in the same directory as the corresponding _implementation file_ ``. The declaration file completely shadows the colocated implementation. In other words, Flow will completely ignore `` and just read `.flow` instead. In the second case, the implementation file is missing entirely. `.flow` is treated as if it is named ``. 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`: ```js import { isLeapYear } from "./Misc"; if (isLeapYear("2020")) console.log("Yay!"); ``` and suppose that `src/Misc.js` has an incompatible implementation of `isLeapYear`: ```js flow-check 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-check declare 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 {#toc-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`: ```js flow-check declare class List { map(f: (x: T) => U): List; } declare function foo(n: number): string; function fooList(ns: List): List { return ns.map(foo); } ``` Just don't forget to replace the declarations with proper implementations. --- --- title: Emacs slug: /editors/emacs --- ### flow-for-emacs {#toc-flow-for-emacs} You can add support for Flow in Emacs by using [flow-for-emacs](https://github.com/flowtype/flow-for-emacs) ### Requirements {#toc-emacs-requirements} * Requires Flow to be installed and available on your path. * Requires projects containing JavaScript files to be initialised with flow init. * Requires JavaScript files to be marked with /* @flow */ at the top. ### Installation {#toc-emacs-installation} ```sh cd ~/.emacs.d/ git clone https://github.com/flowtype/flow-for-emacs.git echo -e "\n(load-file \"~/.emacs.d/flow-for-emacs/flow.el\")" >> ~/.emacs ``` --- --- title: Editors description: "Detailed guides, tips, and resources on how to integrate Flow with different code editors." slug: /editors --- You can benefit from having Flow run as you develop by integrating into your editor. Editor plugins are provided and maintained by the community. If you have trouble configuring or using a specific plugin for your IDE, please visit the project's repo or search for a community provided answer. --- --- title: Sublime Text slug: /editors/sublime-text --- ### Flow For Sublime Text 2 and 3 {#toc-flow-for-sublime-text-2-and-3} [Sublime Text](https://www.sublimetext.com/) can be integrated with Flow by using [Package Control](https://packagecontrol.io) * Install the Package Control plugin if you don't have it * Press Ctrl+Shift+P to bring up the Command Palette (or use Tools > Command Palette menu) * Select Package Control: Install Package * Type 'Flow' to find 'Flow for Sublime Text 2 and 3' * Select 'Flow for Sublime Text 2 and 3' to install ### SublimeLinter-flow {#toc-sublimelinter-flow} You may also wish to install a popular SublimeLinter plugin for Flow like [SublimeLinter-flow](https://packagecontrol.io/packages/SublimeLinter-flow). --- --- title: Vim slug: /editors/vim --- Flow's editor integration is primarily via the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/). There are [many vim LSP clients](https://microsoft.github.io/language-server-protocol/implementors/tools/) to choose from, such as [ALE](#toc-ale). ## ALE {#toc-ale} The Asynchronous Lint Engine (ALE) plugin for Vim 8+ and NeoVim, [vim-ale](https://github.com/w0rp/ale), is a generalized linting engine with support for Flow and many other tools. ### Installation {#toc-installation} Follow the [instructions](https://github.com/w0rp/ale#3-installation) in the ALE README. Configure ALE to use the `flow-language-server` linter for JavaScript files: ```vim " In ~/.vim/ftplugin/javascript.vim, or somewhere similar. " Enables only Flow for JavaScript. See :ALEInfo for a list of other available " linters. NOTE: the `flow` linter uses an old API; prefer `flow-language-server`. let b:ale_linters = ['flow-language-server'] " Or in ~/.vim/vimrc: let g:ale_linters = { \ 'javascript': ['flow-language-server'], \} ``` ## coc.nvim-neovim {#toc-coc-nvim-neovim} [Coc](https://github.com/neoclide/coc.nvim) is an intellisense engine for vim8 & neovim. ### Setup {#toc-setup} ```vim set nocompatible filetype off " install coc.nvim using Plug or preferred plugin manager call plug#begin('~/.vim/plugged') Plug 'neoclide/coc.nvim', {'branch': 'release'} call plug#end() filetype plugin indent on " ======= coc settings set updatetime=300 set shortmess+=c " Use leader T to show documentation in preview window nnoremap t :call show_documentation() function! s:show_documentation() if (index(['vim','help'], &filetype) >= 0) execute 'h '.expand('<cword>') else call CocAction('doHover') endif endfunction " instead of having ~/.vim/coc-settings.json let s:LSP_CONFIG = { \ 'flow': { \ 'command': exepath('flow'), \ 'args': ['lsp'], \ 'filetypes': ['javascript', 'javascriptreact'], \ 'initializationOptions': {}, \ 'requireRootPattern': 1, \ 'settings': {}, \ 'rootPatterns': ['.flowconfig'] \ } \} let s:languageservers = {} for [lsp, config] in items(s:LSP_CONFIG) let s:not_empty_cmd = !empty(get(config, 'command')) if s:not_empty_cmd | let s:languageservers[lsp] = config | endif endfor if !empty(s:languageservers) call coc#config('languageserver', s:languageservers) endif ``` ## LanguageClient-neovim {#toc-languageclient-neovim} Another way to add support for Flow in Vim is to use [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim). * Supports vim 8 and neovim * Adds completions to omnifunc * Checks JavaScript files for type errors on save * Look up types under cursor ### Requirements {#toc-requirements} * Requires Flow to be installed and available on your path. * Requires projects containing JavaScript files to be initialised with flow init. * Requires JavaScript files to be marked with /* @flow */ at the top. ### Pathogen {#toc-pathogen} ```sh cd ~/.vim/bundle git clone git://github.com/autozimu/LanguageClient-neovim.git ``` ### NeoBundle {#toc-neobundle} Add this to your ~/.vimrc ```vim NeoBundleLazy 'autozimu/LanguageClient-neovim', { \ 'autoload': { \ 'filetypes': 'javascript' \ }} ``` With Flow build step, using flow-bin ```vim NeoBundleLazy 'autozimu/LanguageClient-neovim', { \ 'autoload': { \ 'filetypes': 'javascript' \ }, \ 'build': { \ 'mac': 'npm install -g flow-bin', \ 'unix': 'npm install -g flow-bin' \ }} ``` ### VimPlug {#toc-vimplug} ```vim Plug 'autozimu/LanguageClient-neovim', { \ 'branch': 'next', \ 'do': 'bash install.sh && npm install -g flow-bin', \ } ``` ### Setup {#toc-setup} ```vim let g:LanguageClient_rootMarkers = { \ 'javascript': ['.flowconfig', 'package.json'] \ } let g:LanguageClient_serverCommands={ \ 'javascript': ['flow', 'lsp'], \ 'javascript.jsx': ['flow', 'lsp'] \} " check the type under cursor w/ leader T nnoremap t :call LanguageClient_textDocument_hover() nnoremap y :call LanguageClient_textDocument_definition() ``` --- --- title: Visual Studio Code slug: /editors/vscode --- ![Screenshot of Flow Language Support](/img/flow_for_vscode.gif) Support for Flow in [Visual Studio Code](https://code.visualstudio.com/) is provided by the [Flow Language Support](https://marketplace.visualstudio.com/items?itemName=flowtype.flow-for-vscode) extension. It provides all the functionality you would expect: - IntelliSense (Autocomplete) - Go to Definition / Peek Definition - Diagnostics (Errors, Warnings) - Hover type information - Toggleable code coverage reports ## Installation Search for "Flow Language Support" in the VS Code extensions panel or install through the [Marketplace](https://marketplace.visualstudio.com/items?itemName=flowtype.flow-for-vscode). --- --- title: WebStorm slug: /editors/webstorm --- Webstorm installation instructions can be found here: - [WebStorm 2016.3](https://www.jetbrains.com/help/webstorm/2016.3/using-the-flow-type-checker.html) - [WebStorm 2017.1](https://www.jetbrains.com/help/webstorm/2017.1/flow-type-checker.html) --- --- title: Defining enums slug: /enums/defining-enums --- import {SinceVersion} from '../../components/VersionTags'; Learn how to define a Flow Enum. Looking for a quick overview? Check out the [Quickstart Guide](../#toc-quickstart). An enum declaration is a statement. Its name defines both a value (from which to [access its members](../using-enums/#toc-accessing-enum-members), and call its [methods](../using-enums/#toc-methods)), and a type (which can be [used as an annotation](../using-enums/#toc-using-as-a-type-annotation) for the type of its members). Enum members must all be of the same type, and those members can be one of four types: [string](#toc-string-enums), [number](#toc-number-enums), [boolean](#toc-boolean-enums), and [symbol](#toc-symbol-enums). Every enum has some common properties: #### Consistent member type {#toc-consistent-member-type} The type of the enum members must be consistent. For example, you can’t mix `string` and `number` members in one enum. They must all be strings, numbers, or booleans (you do not provide values for `symbol` based enums). #### Member name starting character {#toc-member-name-starting-character} Member names must be valid identifiers (e.g. not start with numbers), and must not start with lowercase `a` through `z`. Names starting with those letters are reserved for enum [methods](../using-enums/#toc-methods) (e.g. `Status.cast(...)`). This is not allowed: ```js flow-check enum Status { active, // Error: names can't start with lowercase 'a' through 'z' } ``` #### Unique member names {#toc-unique-member-names} Member names must be unique. This is not allowed: ```js flow-check enum Status { Active, Active, // Error: the name 'Active` was already used above } ``` #### Literal member values {#toc-literal-member-values} If you specify a value for an enum member, it must be a literal (string, number, or boolean), not a computed value. This is not allowed: ```js flow-check enum Status { Active = 1 + 2, // Error: the value must be a literal } ``` #### Unique member values {#toc-unique-member-values} Member values must be unique. This is not allowed: ```js flow-check enum Status { Active = 1, Paused = 1, // Error: the value has already been used above } ``` #### Fixed at declaration {#toc-fixed-at-declaration} An enum is not extendable, so you can’t add new members after the fact while your code is running. At runtime, enum member values can’t change and the members can’t be deleted. In this way they act like a frozen object. ## String enums {#toc-string-enums} String enums are the default. If you don’t specify an `of` clause (e.g. `enum Status of number {}`, `enum Status of symbol {}`, etc.), and do not specify any values (e.g. `enum Status {Active = 1}`) then the definition will default to be a string enum. Unlike the other types of enums (e.g. number enums), you can either specify values for the enum members, or not specify values and allow them to be defaulted. If you don’t specify values for your enum members, they default to strings which are the same as the name of your members. ```js flow-check enum Status { Active, Paused, Off, } ``` Is the same as: ```js flow-check enum Status { Active = 'Active', Paused = 'Paused', Off = 'Off', } ``` You must consistently either specify the value for all members, or none of the members. This is not allowed: ```js flow-check enum Status { Active = 'active', Paused = 'paused', Off, // Error: you must specify a value for all members (or none of the members) } ``` Optionally, you can use an `of` clause: ```js flow-check enum Status of string { Active, Paused, Off, } ``` We infer the type of the enum based on its values if there is no `of` clause. Using an `of` clause will ensure that if you use incorrect values, the error message will always interpret it as an enum of that type. ## Number enums {#toc-number-enums} Number enums must have their values specified. You can specify a number enum like this: ```js flow-check enum Status { Active = 1, Paused = 2, Off = 3, } ``` Optionally, you can use an `of` clause. This does not affect the type-checking behavior of a valid Flow Enum, it just ensures that all enum members are `number`s as the definition site. ```js flow-check enum Status of number { Active = 1, Paused = 2, Off = 3, } ``` We do not allow defaulting of number enums (unlike some other languages), because if a member from the middle of such an enum is added or removed, all subsequent member values would be changed. This can be unsafe (e.g. push safety, serialization, logging). Requiring the user to be explicit about the renumbering makes them think about the consequences of doing so. The value provided must be a number literal. Negative numbers are not literals in JS, but since Flow version 0.234 we allow negative number initializers as well. Example : ```js flow-check enum Status { Active = 1, Paused = 0, Off = -1, } ``` ## Boolean enums {#toc-boolean-enums} Boolean enums must have their values specified. Boolean enums can only have two members. You can specify a boolean enum like this: ```js flow-check enum Status { Active = true, Off = false, } ``` Optionally, you can use an `of` clause. This does not affect the type-checking behavior of a valid Flow Enum, it just ensures that all enum members are `boolean`s as the definition site. ```js flow-check enum Status of boolean { Active = true, Off = false, } ``` ## Symbol enums {#toc-symbol-enums} Symbol enums can’t have their values specified. Each member is a new symbol, with the symbol description set to the name of the member. You must use the `of` clause with symbol enums, to distinguish them from string enums, which are the default when omitting values. You can specify a symbol enum like this: ```js flow-check enum Status of symbol { Active, Paused, Off, } ``` ## Flow Enums with Unknown Members {#toc-flow-enums-with-unknown-members} You can specify that your enum contains "unknown members" by adding a `...` to the end of the declaration: ```js flow-check enum Status { Active, Paused, Off, ... } const status: Status = Status.Active; switch (status) { case Status.Active: break; case Status.Paused: break; case Status.Off: break; } match (status) { Status.Active => {} Status.Paused => {} Status.Off => {} } ``` When this is used, Flow will always require a `default` (for `switch`) or wildcard `_` (for [`match`](../../match))when [checking the enum](../using-enums/#toc-exhaustive-checking-with-unknown-members), even if all known enum members are checked. The `default`/`_` checks for "unknown" members you haven't explicitly listed. This feature is useful when an enum value crosses some boundary and the enum declaration on each side may have different members. For example, an enum definition which is used on both the client and the server: an enum member could be added, which would be immediately seen by the server, but could be sent to an outdated client which isn't yet aware of the new member. One use case for this would be the JS output of [GraphQL Enums](https://graphql.org/learn/schema/#enumeration-types): Flow Enums with unknown members could be used instead of the added `'%future added value'` member. ## Enums at runtime {#toc-enums-at-runtime} Enums exist as values at runtime. We use a [Babel transform](https://www.npmjs.com/package/babel-plugin-transform-flow-enums) to transform Flow Enum declarations into calls to the [enums runtime](https://www.npmjs.com/package/flow-enums-runtime) (read more in the [enabling enums documentation](../enabling-enums/)). We use a runtime so all enums can share an implementation of the enum [methods](../using-enums/#toc-methods). We use `Object.create(null)` for enums' prototype (which has the enum methods), so properties in `Object.prototype` will not pollute enums. The only own properties of the enum object are the enum members. The members are non-enumerable (use the [`.members()` method](../using-enums/#toc-members) for that). The entire enum object is frozen, so it cannot be modified. ## Style guide {#toc-style-guide} #### Naming enums {#toc-naming-enums} We encourage you to define enum names in `PascalCase`, following the naming conventions of other types. All caps names (e.g. `STATUS`) are harder to read and discouraged. We encourage you to name enums in the singular. E.g. `Status`, not `Statuses`. Just like the type of `true` and `false` is `boolean`, not `booleans`. Don't append `Enum` to the name (e.g. don't name your enum `StatusEnum`). This is unnecessary, just like we don't append `Class` to every class name, and `Type` to every type alias. #### Naming enum members {#toc-naming-enum-members} We encourage you to define enum member names in `PascalCase`. All caps names (e.g. `ACTIVE`) are harder to read and discouraged. Additionally, since Flow enforces that these are constants, you don't need to use the name to signal that intent to the programmer. See also: the rule about [enum member name starting characters](#toc-member-name-starting-character). #### Don't create a separate type {#toc-don-t-create-a-separate-type} A Flow Enum, like a class, is both a type and a value. You don't need to create a separate type alias, you can use the enum name. #### Use dot access for accessing members {#toc-use-dot-access-for-accessing-members} Prefer `Status.Active` vs. `const {Active} = Status;`. This makes it easier find uses of the enum with text search, and makes it clearer to the reader what enum is involved. Additionally, this is required for [switch statements involving enums](../using-enums/#toc-exhaustively-checking-enums-with-a-switch). --- --- title: Enabling enums in your project slug: /enums/enabling-enums --- ## Upgrade tooling {#toc-upgrade-tooling} To enable Flow Enums in your repo, you must first update the following packages: - Upgrade to at least Flow 0.159 - Flow needs to have some configuration set to enable enums - see below. - Upgrade [Prettier](https://prettier.io/) to at least version 2.2 - As of that version, Prettier can handle parsing and pretty printing Flow Enums out of the box. - You must use the `flow` [parser option](https://prettier.io/docs/en/options.html#parser) for JavaScript files to be able to format Flow Enums. - Upgrade [Babel](https://babeljs.io/) to at least version 7.13.0 - As of that version, Babel can parse Flow Enums. However, to enable this parsing some configuration needs to be supplied, and additionally it does not include the transform required - see below. - Upgrade [jscodeshift](https://github.com/facebook/jscodeshift) to at least version 0.11.0 - Upgrade [hermes-parser](https://www.npmjs.com/package/hermes-parser) to at least version 0.4.8 - For ESLint, either: - Use [hermes-eslint](https://www.npmjs.com/package/hermes-eslint) as your ESLint parser, at least version 0.4.8 - Or upgrade [babel-eslint](https://github.com/babel/babel-eslint) to version 10.1.0 - As of that version, `babel-eslint` can handle Flow Enums out of the box. - Do not upgrade to 11.x, this branch does not support Flow Enums. - Or use another solution using Babel 7.13.0 or later, with Flow enabled - this may also work If you have any other tool which examines your code, you need to update it as well. If it uses [flow-parser](https://www.npmjs.com/package/flow-parser), [hermes-parser](https://www.npmjs.com/package/hermes-parser) or `@babel/parser`, upgrade those as per the instructions above. If it uses some other parser, you will need to implement parsing Flow Enums in that parser. You can look at the existing code in Babel, Flow, and Hermes parsers to guide your work. ## Enable enums {#toc-enable-enums} - In your `.flowconfig`, under the `[options]` heading, add `enums=true` - Add the Flow Enums Babel transform. It turns enum declaration AST nodes into calls to the runtime: [babel-plugin-transform-flow-enums](https://www.npmjs.com/package/babel-plugin-transform-flow-enums). Add it to your development dependencies and adjust your Babel configuration to use the transform. The transform by default requires the runtime package directly (below), but you can configure this. - Add the Flow Enum runtime package to your production dependencies. This will be required and used at runtime to create Flow Enums: [flow-enums-runtime](https://www.npmjs.com/package/flow-enums-runtime) ## Enable suggested ESLint rules {#toc-enable-suggested-eslint-rules} Enums can be exhaustively checked in `switch` statements, so may increase the use of `switch` statements compared to before. To prevent common issues with `switch` statements, we suggest you enable these ESLint rules (at least as warnings): - [no-fallthrough](https://eslint.org/docs/rules/no-fallthrough): This prevents the user from accidentally forgetting a `break` statement at the end of their switch case, while supporting common use-cases. - [no-case-declarations](https://eslint.org/docs/rules/no-case-declarations): This prevents lexicaly scoped declarations (`let`, `const`) from being introduced in a switch case, without wrapping that case in a new block. Otherwise, declarations in different cases could conflict. We also have some Flow Enums specific rules as part of [eslint-plugin-fb-flow](https://www.npmjs.com/package/eslint-plugin-fb-flow): - [use-flow-enums](https://www.npmjs.com/package/eslint-plugin-fb-flow#use-flow-enums): Suggests that enum-like `Object.freeze` and `keyMirror` usage be turned into Flow Enums instead. - [flow-enums-default-if-possible](https://www.npmjs.com/package/eslint-plugin-fb-flow#flow-enums-default-if-possible): Auto-fixes string enums with specified values identical to the member names to defaulted enums. - [no-flow-enums-object-mapping](https://www.npmjs.com/package/eslint-plugin-fb-flow#no-flow-enums-object-mapping): Suggests using a function with a switch to map enum values to other values, instead of an object literal. --- --- title: Flow Enums description: "Define a fixed set of constants which create their own type. Exhaustively checked in switch statements." slug: /enums --- Flow Enums define a fixed set of constants which create their own type. Unlike other features of Flow, Flow Enums exist as values at runtime, as well as existing as types. [Read how to enable Flow Enums in your project](./enabling-enums/). ## Benefits {#toc-benefits} Enums provide several benefits over existing patterns: * Reduce repetition: Enum declarations provide both the type and the value of the enum. * Improve Flow performance: Enums are guaranteed to have good type-checking performance, unlike unions which may be expensive to type-check in certain situations. * Enable new functionality: Enums come with a `cast` [method](./using-enums/#toc-methods), which converts from a primitive type to an enum type safely. * Enhance safety: Enums define their own type which does not implicitly coerce to and from other types (e.g. from `string`s), and are required to be [exhaustively checked in switch statements](./using-enums/#toc-exhaustively-checking-enums-with-a-switch). These properties can help prevent logic bugs. ## Quickstart {#toc-quickstart} #### [Defining enums](./defining-enums) {#toc-defining-enums-defining-enums} An enum named `Status` with three members: `Active`, `Paused`, and `Off`. ```js flow-check enum Status { Active, Paused, Off, } ``` By default, enums define members with string values which mirror their names. You can also explicitly set values: ```js flow-check enum Status { Active = 'active', Paused = 'paused', Off = 'off', } ``` You can use numbers as well: ```js flow-check enum Status { Active = 1, Paused = 2, Off = 3, } ``` Values must be unique, literals, and all of the same type. Check out the [full docs on defining enums](./defining-enums/) to learn more. #### [Using enums](./using-enums/) {#toc-using-enums-using-enums} To access an enum member, use dot access: ```js Status.Active ``` To use the enum type as an annotation, use the enum name: ```js const status: Status = Status.Active; ``` Cast from the representation type (in this case, a `string`) to the enum type: ```js const status: Status | void = Status.cast(someString); ``` You can easily provide a default value with the `??` operator: ```js const status: Status = Status.cast(someString) ?? Status.Off; ``` Read more about the [other methods enums provide](./using-enums/#toc-methods), including `isValid`, `members`, and `getName`. Cast an enum type to its representation type (must be done explicitly): ```js status as string ``` Checks of enums in `switch` statements are exhaustive - we ensure you check all members: ```js flow-check enum Status { Active, Paused, Off, } const status: Status = Status.Active; // ERROR: Incomplete exhaustive check switch (status) { case Status.Active: break; case Status.Paused: break; // We forgot to add `case: Status.Off:` here, resulting in error above. // Using `default:` would also work to check all remaining members. } ``` Read more about [exhaustively checking enums](./using-enums/#toc-exhaustively-checking-enums-with-a-switch). Check out the [the full docs on using enums](./using-enums/) to learn more. ## When to use Flow Enums {#toc-when-to-use-flow-enums} If you previously defined a union type of literals, you can use an enum to define that type instead. Instead of ```js flow-check type Status = | 'Active' | 'Paused' | 'Off'; const x: Status = 'Active'; ``` or ```js flow-check const Status = Object.freeze({ Active: 'Active', Paused: 'Paused', Off: 'Off', }); type StatusType = keyof typeof Status; const x: StatusType = Status.Active; ``` you can use: ```js flow-check enum Status { Active, Paused, Off, } const x: Status = Status.Active; ``` See [migrating from legacy patterns](./migrating-legacy-patterns) to learn more about migrating legacy JavaScript enum patterns to Flow Enums. ## When to not use Flow Enums {#toc-when-to-not-use-flow-enums} Enums are designed to cover many use cases and exhibit certain benefits. The design makes a variety of trade-offs to make this happen, and in certain situations, these trade-offs might not be right for you. In those cases, you can continue to use existing patterns to satisfy your use cases. [Read more about those situations](./using-enums/#toc-when-to-not-use-enums). --- --- title: Migrating from legacy patterns slug: /enums/migrating-legacy-patterns --- Learn how to migrate to Flow Enums from legacy JavaScript enum patterns like `Object.freeze`. First, learn how to [update the enum definition site](#toc-updating-definitions), and next learn how to [update files that import and use the enum](#toc-updating-usage). ## Updating definitions {#toc-updating-definitions} #### Object.freeze {#toc-object-freeze} If you are using `Object.freeze`, you can migrate to an enum if the values of the object are: * All the same primitive type, and that type is `boolean`, `string`, `number`, or `symbol`. * All literals. * Contain no duplicate values. Replace ```js flow-check const Status = Object.freeze({ Active: 1, Paused: 2, Off: 3, }); export type StatusType = Values; export default Status; ``` with ```js flow-check export default enum Status { Active = 1, Paused = 2, Off = 3, } ``` - Check to ensure that the key names do not start with lowercase ‘a’-‘z’ (disallowed in enums). If they do, you’ll need to rename the member names. - Remove any usage of `keyof ...` or `Values<...>` on the enum type, these are no longer needed as a Flow Enum defines a type itself (its name). - Delete any type exports based on the enum, as you just need to export the Flow Enum. A Flow Enum acts as both a type and a value (like a class). Then, take a look at [how to update files that import and use the enum](#toc-updating-usage). #### keyMirror {#toc-keymirror} The `keyMirror` utility creates an object whose values are mirrors of its key names. You can replace `keyMirror` usage with a string based enum. Replace ```js import keyMirror from 'keyMirror'; const Status = keyMirror({ Active: null, Paused: null, Off: null, }); export type StatusType = keyof typeof Status; export default Status; ``` with ```js flow-check export default enum Status { Active, Paused, Off, } ``` - Check to ensure that the key names do not start with lowercase ‘a’-‘z’ (disallowed in enums). If they do, you’ll need to rename the member names. - Remove any usage of `keyof ...` on the enum type, it's no longer needed as a Flow Enum defines a type itself (its name). - Delete any type exports based on the enum, you just need to export the Flow Enum. A Flow Enum acts as both a type and a value (like a class). Then, take a look at [how to update files that import and use the enum](#toc-updating-usage). ## Updating usage {#toc-updating-usage} #### Fix type imports {#toc-fix-type-imports} Previous patterns required you to export (and then import) a type separate from the enum itself. Flow Enums are both types and values (like a class), so you just need to export the Flow Enum itself. Since there is now one export, you only need one import. Read more about [exporting enums](../using-enums/#toc-exporting-enums) and [importing enums](../using-enums/#toc-importing-enums). If you previously had: ```js flow-check const Status = Object.freeze({ Active: 1, Paused: 2, Off: 3, }); export type StatusType = Values; export default Status; ``` And you've replaced it with: ```js flow-check export default enum Status { Active = 1, Paused = 2, Off = 3, } ``` Then you need to fix the imports as well: ##### If both type and value were imported {#toc-if-both-type-and-value-were-imported} For a user of the enum, if you previously imported both the type and the value, you can delete the type import and update annotations used. Change ```js import type {StatusType} from 'status'; import Status from 'status'; const myStatus: StatusType = Status.Active; ``` to ```js // Type import is deleted import Status from 'status'; const myStatus: Status = Status.Active; // Changed type annotation to just `Status` ``` ##### If only the type was imported {#toc-if-only-the-type-was-imported} For a user of the enum, if you previously imported just the type, change the type import to a default import rather than a named import. Change ```js import type {StatusType} from 'status'; function isActive(status: StatusType) { ... } ``` to ```js // Remove the braces `{` `}` and changed the name - this is a default import now import type Status from 'status'; function isActive(status: Status) { ... } // Changed type annotation to just `Status` ``` #### Mapping enums to other values {#toc-mapping-enums-to-other-values} Sometimes you want to map from an enum value to some other value. Previously, we sometimes used object literals for this. With Flow Enums, use a function with a `switch` instead. The switch is [exhaustively checked](../using-enums/#toc-exhaustively-checking-enums-with-a-switch), so Flow will ensure you update your mapping when you add or remove Flow Enum members. Replace this pattern ```js const STATUS_ICON: {[Status]: string} = { [Status.Active]: 'green-checkmark', [Status.Paused]: 'grey-pause', [Status.Off]: 'red-x', }; const icon = STATUS_ICON[status]; ``` with ```js function statusIcon(status: Status): string { switch (status) { case Status.Active: return 'green-checkmark'; case Status.Paused: return 'grey-pause'; case Status.Off: return 'red-x'; } } const icon = statusIcon(status); ``` Read more about [mapping enums to other values](../using-enums/#toc-mapping-enums-to-other-values). #### Usage as the representation type (e.g. a string) {#toc-usage-as-the-representation-type-e-g-a-string} You can't use a Flow Enum directly as its representation type (e.g. a `string`). If you get Flow errors about using an enum as its representation type, first try to refactor your code so that it expects the enum type instead of the representation type (e.g. change annotations from `string` to `Status`). If you really want to use the enum as its representation type, you can add in explicit casts. See [casting to representation type](../using-enums/#toc-casting-to-representation-type). #### Casting to the enum type {#toc-casting-to-the-enum-type} If before you cast from an enum's representation type (e.g. `string`) to the enum type with something like this: ```js function castToStatus(input: number): StatusType | void { switch(input) { case 1: return Status.Active; case 2: return Status.Paused; case 3: return Status.Off; default: return undefined; } } castToStatus(x); ``` You can now just use the [cast](../using-enums/#toc-cast) method: ```js Status.cast(x); ``` #### Update switch statements {#toc-update-switch-statements} Flow Enums are exhaustively checked in `switch` statements. You might need to update your code when you are switching over an enum value. Read more at [exhaustively checking enums in switch statements](../using-enums/#toc-exhaustively-checking-enums-with-a-switch). #### Operations over enum members {#toc-operations-over-enum-members} If previously you used functionality like `Object.values`, `Object.keys`, or `for-in` loops to get and operate on the enum members, you can use the [members method](../using-enums/#toc-members) instead. --- --- title: Using enums slug: /enums/using-enums --- import {SinceVersion} from '../../components/VersionTags'; Flow Enums are not a syntax for [union types](../../types/unions/). They are their own type, and each member of a Flow Enum has the same type. Large union types can cause performance issues, as Flow has to consider each member as a separate type. With Flow Enums, no matter how large your enum is, Flow will always exhibit good performance as it only has one type to keep track of. We use the following enum in the examples below: ```js enum Status { Active, Paused, Off, } ``` ### Accessing enum members {#toc-accessing-enum-members} Access members with the dot syntax: ```js const status = Status.Active; ``` You can’t use computed access: ```js flow-check enum Status { Active, Paused, Off, } const x = "Active"; Status[x]; // Error: computed access on enums is not allowed ``` ### Using as a type annotation {#toc-using-as-a-type-annotation} The enum declaration defines both a value (from which you can access the enum members and methods) and a type of the same name, which is the type of the enum members. ```js function calculateStatus(): Status { ... } const status: Status = calculateStatus(); ``` ### Casting to representation type {#toc-casting-to-representation-type} Enums do not implicitly coerce to their representation type or vice-versa. If you want to convert from the enum type to the representation type, you can use an explicit cast `x as string`: ```js flow-check enum Status {Active, Paused, Off} const s: string = Status.Active; // Error: 'Status' is not compatible with 'string' declare const status: Status; const statusString: string = status as string; ``` You can also call `.valueOf()` on the enum value . This is particularly useful if you are dealing with [abstract enums](#toc-abstract-enums) and don't know the representation type. ```js flow-check enum Status {Active, Paused, Off} declare const status: Status; const statusString: string = status.valueOf(); ``` To convert from a nullable enum type to nullable representation type, you can do: ```js flow-check enum Status {Active, Paused, Off} declare const maybeStatus: ?Status; // Using `as` cast and `&&`: const maybeStatusString1: ?string = maybeStatus && (maybeStatus as string); // Using `.valueOf()` and optional chaining: const maybeStatusString2: ?string = maybeStatus?.valueOf(); ``` If you want to convert from the representation type (e.g. `string`) to an enum type (if valid), check out the [cast method](#toc-cast). ### Methods {#toc-methods} Enum declarations also define some helpful methods. Below, `TEnum` is the type of the enum (e.g. `Status`), and `TRepresentationType` is the type of the representation type for that enum (e.g. `string`). #### .cast {#toc-cast} Type: `cast(input: ?TRepresentationType): TEnum | void` The `cast` method allows you to safely convert a primitive value, like a `string`, to the enum type (if it is a valid value of the enum), and `undefined` otherwise. ```js const data: string = getData(); const maybeStatus: Status | void = Status.cast(data); if (maybeStatus != null) { const status: Status = maybeStatus; // do stuff with status } ``` Set a default value in one line with the `??` operator: ```js const status: Status = Status.cast(data) ?? Status.Off; ``` The type of the argument of `cast` depends on the type of enum. If it is a [string enum](../defining-enums/#toc-string-enums), the type of the argument will be `string`. If it is a [number enum](../defining-enums/#toc-number-enums), the type of the argument will be `number`, and so on. If you wish to cast a `unknown` value, first use a `typeof` refinement: ```js const data: unknown = ...; if (typeof data === 'string') { const maybeStatus: Status | void = Status.cast(data); } ``` `cast` uses `this` (representing the object of enum members), so if you want to pass the function itself as a value, you should use an arrow function. For example: ```js const strings: Array = ...; // WRONG: const statuses: Array = strings.map(Status.cast); const statuses: Array = strings.map((input) => Status.cast(input)); // Correct ``` Runtime cost: For [mirrored string enums](../defining-enums/#toc-string-enums) (e.g `enum E {A, B}`), as the member names are the same as the values, the runtime cost is constant - equivalent to calling `.hasOwnProperty`. For other enums, a `Map` is created on the first call, and subsequent calls simply call `.has` on the cached map. Thus the cost is amoritzed constant. #### .isValid {#toc-isvalid} Type: `isValid(input: ?TRepresentationType): boolean` The `isValid` method is like `cast`, but simply returns a boolean: `true` if the input supplied is a valid enum value, and `false` if it is not. ```js const data: string = getData(); const isStatus: boolean = Status.isValid(data); ``` `isValid` uses `this` (representing the object of enum members), so if you want to pass the function itself as a value, you should use an arrow function. For example: ```js const strings: Array = ...; // WRONG: const statusStrings = strings.filter(Status.isValid); const statusStrings = strings.filter((input) => Status.isValid(input)); // Correct ``` Runtime cost: The same as described under `.cast` above. #### .members {#toc-members} Type: `members(): Iterator` The `members` method returns an [iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#iterators) (that is iterable) of all the enum members. ```js const buttons = []; function getButtonForStatus(status: Status) { ... } for (const status of Status.members()) { buttons.push(getButtonForStatus(status)); } ``` The iteration order is guaranteed to be the same as the order of the members in the declaration. The enum is not enumerable or iterable itself (e.g. a for-in/for-of loop over the enum will not iterate over its members), you have to use the `.members()` method for that purpose. You can convert the iterable into an `Array` using: `Array.from(Status.members())`. You can make use of [`Array.from`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)'s second argument to map over the values at the same time you construct the array: e.g. ```js const buttonArray = Array.from( Status.members(), status => getButtonForStatus(status), ); ``` #### .getName {#toc-getname} Type: `getName(value: TEnum): string` The `getName` method maps enum values to the string name of that value's enum member. When using `number`/`boolean`/`symbol` enums, this can be useful for debugging and for generating internal CRUD UIs. For example: ```js enum Status { Active = 1, Paused = 2, Off = 3, } const status: Status = ...; console.log(Status.getName(status)); // Will print a string, either "Active", "Paused", or "Off" depending on the value. ``` Runtime cost: The same as described under `.cast` above. A single cached reverse map from enum value to enum name is used for `.cast`, `.isValid`, and `.getName`. The first call of any of those methods will create this cached map. ### Exhaustively checking enums with a `switch` {#toc-exhaustively-checking-enums-with-a-switch} When checking an enum value in a `switch` statement, we enforce that you check against all possible enum members, and don’t include redundant cases. This helps ensure you consider all possibilities when writing code that uses enums. It especially helps with refactoring when adding or removing members, by pointing out the different places you need to update. If you have [match](../../match) enabled, use `match` expressions and statements instead of `switch` statements. ```js const status: Status = ...; switch (status) { // Good, all members checked case Status.Active: break; case Status.Paused: break; case Status.Off: break; } ``` You can use `default` to match all members not checked so far: ```js switch (status) { case Status.Active: break; default: // When `Status.Paused` or `Status.Off` break; } ``` You can check multiple enum members in one switch case: ```js switch (status) { case Status.Active: case Status.Paused: break; case Status.Off: break; } ``` You must match against all of the members of the enum (or supply a `default` case): ```js flow-check enum Status { Active = 1, Paused = 2, Off = 3, } const status: Status = Status.Active; // Error: you haven't checked 'Status.Off' in the switch switch (status) { case Status.Active: break; case Status.Paused: break; } ``` You can’t repeat cases (as this would be dead code!): ```js flow-check enum Status { Active = 1, Paused = 2, Off = 3, } const status: Status = Status.Active; switch (status) { case Status.Active: break; case Status.Paused: break; case Status.Off: break; case Status.Paused: // Error: you already checked for 'Status.Paused' break; } ``` A `default` case is redundant if you’ve already matched all cases: ```js flow-check enum Status { Active = 1, Paused = 2, Off = 3, } const status: Status = Status.Active; switch (status) { case Status.Active: break; case Status.Paused: break; case Status.Off: break; default: // Error: you've already checked all cases, the 'default' is redundant break; } // The following is OK because the `default` covers the `Status.Off` case: switch (status) { case Status.Active: break; case Status.Paused: break; default: break; } ``` Except if you are switching over an enum with [unknown members](../defining-enums/#toc-flow-enums-with-unknown-members). If you nest exhaustively checked switches inside exhaustively checked switches, and are returning from each branch, you must add a `break;` after the nested switch: ```js switch (status) { case Status.Active: return 1; case Status.Paused: return 2; case Status.Off: switch (otherStatus) { case Status.Active: return 1; case Status.Paused: return 2; case Status.Off: return 3; } break; } ``` Remember, you can add blocks to your switch cases. They are useful if you want to use local variables: ```js switch (status) { case Status.Active: { const x = f(); ... break; } case Status.Paused: { const x = g(); ... break; } case Status.Off: { const y = ...; ... break; } } ``` If you didn't add blocks in this example, the two declarations of `const x` would conflict and result in an error. Enums are not checked exhaustively in `if` statements, or other contexts other than `switch` statements and `match` expressions/statements. ### Exhaustively checking enums with a `match` All values are exhaustively checked in a [match](../../match), including Flow Enums: ```js const status: Status = ...; match (status) { // Good, all members checked Status.Active => {} Status.Paused => {} Status.Off => {} } ``` You can use a [wildcard](../../match/patterns/#wildcard-patterns) `_` to match all members not checked so far: ```js match (status) { Status.Active => {} _ => {} // When `Status.Paused` or `Status.Off` } ``` You can check [multiple](../../match/patterns/#or-patterns) enum members in one `match` case: ```js match (status) { Status.Active | Status.Paused => {} Status.Off => {} } ``` You must match against all of the members of the enum (or supply a wildcard `_` case): ```js flow-check enum Status { Active = 1, Paused = 2, Off = 3, } const status: Status = Status.Active; // Error: you haven't checked 'Status.Off' in the match match (status) { Status.Active => {} Status.Paused => {} } ``` ### Exhaustive checking with unknown members {#toc-exhaustive-checking-with-unknown-members} If your enum has [unknown members](../defining-enums/#toc-flow-enums-with-unknown-members) (specified with the `...`), e.g. ```js enum Status { Active, Paused, Off, ... } ``` Then a `default` is always required when switching over the enum, and a wildcard `_` is always required when using a [`match`](../../match). The `default`/`_` checks for "unknown" members you haven't explicitly listed. ```js switch (status) { case Status.Active: break; case Status.Paused: break; case Status.Off: break; default: // Checks for members not explicitly listed } match (status) { Status.Active => {} Status.Paused => {} Status.Off => {} _ => { // Checks for members not explicitly listed } } ``` You can use the `require-explicit-enum-switch-cases` [Flow Lint](../../linting/flowlint-comments/) for `switch` or the `require-explicit-enum-checks` lint for `match` to require that all known members are explicitly listed as cases. For example: ```js flow-check enum Status { Active = 1, Paused = 2, Off = 3, ... } const status: Status = Status.Active; // flowlint-next-line require-explicit-enum-switch-cases:error switch (status) { case Status.Active: break; case Status.Paused: break; default: break; } // flowlint-next-line require-explicit-enum-checks:error match (status) { Status.Active => {} Status.Paused => {} _ => {} } ``` You can fix if by doing: ```js flow-check enum Status { Active = 1, Paused = 2, Off = 3, ... } const status: Status = Status.Active; // flowlint-next-line require-explicit-enum-switch-cases:error switch (status) { case Status.Active: break; case Status.Paused: break; case Status.Off: // Added the missing `Status.Off` case break; default: break; } // flowlint-next-line require-explicit-enum-checks:error match (status) { Status.Active => {} Status.Paused => {} Status.Off => {} // Added the missing `Status.Off` case _ => {} } ``` The `require-explicit-enum-switch-cases`/`require-explicit-enum-checks` lints are not enabled globally, but rather on a per-`switch`/`match` basis when you want the behavior. With normal enums, for each `switch` statement or `match`, you can either provide a `default`/`_` or not, and thus decide if you want to require each case explicitly listed or not. Similarly for Flow Enums with unknown members, you can also enable this lint on a per-`switch`/`match` basis. The `require-explicit-enum-switch-cases` lint works for switches of regular Flow Enum types as well. It in effect bans the usage of `default` in that `switch` statement, by requiring the explicit listing of all enum members as cases. ### Mapping enums to other values {#toc-mapping-enums-to-other-values} There are a variety of reasons you may want to map an enum value to another value, e.g. a label, icon, element, and so on. With previous patterns, it was common to use object literals for this purpose, however with Flow Enums we prefer functions which contain a switch, or better yet [match](../../match) expressions if enabled, as we can exhaustively check these. Instead of: ```js const STATUS_ICON: {[Status]: string} = { [Status.Active]: 'green-checkmark', [Status.Paused]: 'grey-pause', [Status.Off]: 'red-x', }; const icon = STATUS_ICON[status]; ``` Which doesn't actually guarantee that we are mapping each `Status` to some value, use: ```js flow-check enum Status { Active, Paused, Off, } declare const status: Status; function getStatusIcon(status: Status): string { switch (status) { case Status.Active: return 'green-checkmark'; case Status.Paused: return 'grey-pause'; case Status.Off: return 'red-x'; } } const icon = getStatusIcon(status); ``` Or with `match`: ```js flow-check enum Status { Active, Paused, Off, } declare const status: Status; const icon = match(status) { Status.Active => 'green-checkmark', Status.Paused => 'grey-pause', Status.Off => 'red-x', }; ``` In the future if you add or remove an enum member, Flow will tell you to update the `switch` or `match` as well so it's always accurate. If you actually want a dictionary which is not exhaustive, you can use a [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map): ```js const counts = new Map([ [Status.Active, 2], [Status.Off, 5], ]); const activeCount: Status | void = counts.get(Status.Active); ``` Flow Enums cannot be used as keys in object literals, as [explained later on this page](#toc-distinct-object-keys). ### Enums in a union {#toc-enums-in-a-union} If your enum value is in a union (e.g. `?Status`), first refine to only the enum type: ```js const status: ?Status = ...; if (status != null) { status as Status; // 'status' is refined to 'Status' at this point switch (status) { case Status.Active: break; case Status.Paused: break; case Status.Off: break; } } ``` If you want to refine *to* the enum value, you can use `typeof` with the representation type, for example: ```js const val: Status | number = ...; // 'Status' is a string enum if (typeof val === 'string') { val as Status; // 'val' is refined to 'Status' at this point switch (val) { case Status.Active: break; case Status.Paused: break; case Status.Off: break; } } ``` ### Exporting enums {#toc-exporting-enums} An enum is a type and a value (like a class is). To export both the type and the value, export it like a you would a value: ```js flow-check export enum Status {} ``` Or, as the default export (note: you must always specify an enum name, `export default enum {}` is not allowed): ```js flow-check export default enum Status {} ``` Using CommonJS: ```js flow-check enum Status {} module.exports = Status; ``` To export **only** its type, but not the value, you can do: ```js flow-check enum Status {} export type {Status}; ``` Other functions within the file will still have access to the enum implementation. ### Importing enums {#toc-importing-enums} If you have exported an enum like this: ```js flow-check // status.js export default enum Status { Active, Paused, Off, } ``` You can import it as both a value and a type like this: ```js import Status from 'status'; const x: Status /* used as type */ = Status.Active /* used as value */; ``` If you only need to use the type, you can import it as a type: ```js import type Status from 'status'; function printStatus(status: Status) { ... } ``` Using CommonJS: ```js const Status = require('status'); ``` ### Abstract enums {#toc-abstract-enums} You can write code that operates on Flow Enums in a generic way using two types: `Enum<>` and `EnumValue<>`, which accept any Flow Enum and its values. #### EnumValue<> `EnumValue<>` accepts any Flow Enum value. Want to narrow it down to enum values with a specific representation type? Just add a type argument: ```js flow-check enum Status {Active, Paused, Off} Status.Active as EnumValue<>; // OK Status.Active as EnumValue; // OK - its a string enum Status.Active as EnumValue; // ERROR - not a number enum ``` The new `EnumRepresentationTypes` type represents all the valid representation types: `string`, `number`, etc. Flow Enum values don’t implicitly coerce to their representation type, so we allow [explicit conversion](#toc-casting-to-representation-type) with casts like `Status.Active as string`. With `EnumValue<>` you might not know the specific representation type, so we now allow casts using `.valueOf()` directly on the enum value. For example: ```js flow-check function f(e: EnumValue<>) { const x: EnumRepresentationTypes = e.valueOf(); // OK } ``` #### Enum<> `Enum<>` accepts any Flow Enum - the enum itself, rather than its value. You can optionally supply a type argument to restrict it to enums with a certain enum value, which you can pair with the `EnumValue` type above: ```js flow-check enum Status {Active, Paused, Off} Status as Enum<>; // OK Status as Enum; // OK Status as Enum>; // OK ``` With the `Enum<>` type you can use all the Flow Enum [methods](#toc-methods) like `.cast` and `.members`. This lets you craft code that generically handles Flow Enums, for example creating a full React selector component from only a Flow Enum: ##### Usage ```js enum Status { Active, Paused, Off, } ``` ##### Definition ```js flow-check import * as React from 'react'; import {useCallback, useMemo, useState} from 'react'; component Selector< TEnumValue: EnumValue, >( items: Enum, callback: (TEnumValue) => void, ) { // Typing the `useState` selector with the enum value generic const [value, setValue] = useState(null); const handleChange = useCallback((e: SyntheticInputEvent<>) => { // Using the `.cast` method const value = items.cast(e.target.value); if (value == null) { throw new Error("Invalid value"); } setValue(value); callback(value); }, [items, callback]); return
    {Array.from(items.members(), item => // Using the `.members()` method
  • )}
; } ``` ### When to not use enums {#toc-when-to-not-use-enums} Enums are designed to cover many use cases and exhibit certain benefits. The design makes a variety of trade-offs to make this happen, and in certain situations, these trade-offs might not be right for you. In these cases, you can continue to use existing patterns to satisfy your use cases. #### Distinct object keys {#toc-distinct-object-keys} You can’t use enum members as distinct object keys. The following pattern works because the types of `LegacyStatus.Active` and `LegacyStatus.Off` are different. One has the type `'Active'` and one has the type `'Off'`. ```js flow-check const LegacyStatus = Object.freeze({ Active: 'Active', Paused: 'Paused', Off: 'Off', }); const o = { [LegacyStatus.Active]: "hi", [LegacyStatus.Off]: 1, }; const x: string = o[LegacyStatus.Active]; // OK const y: number = o[LegacyStatus.Off]; // OK const z: boolean = o[LegacyStatus.Active]; // Error - as expected ``` We can’t use the same pattern with enums. All enum members have the same type, the enum type, so Flow can’t track the relationship between keys and values. If you wish to map from an enum value to another value, you should use a [function with an exhaustively-checked switch instead](#toc-mapping-enums-to-other-values). #### Disjoint object unions {#toc-disjoint-object-unions} A defining feature of enums is that unlike unions, each enum member does not form its own separate type. Every member has the same type, the enum type. This allows enum usage to be analyzed by Flow in a consistently fast way, however it means that in certain situations which require separate types, we can’t use enums. Consider the following union, following the [disjoint object union](../../types/unions/#toc-disjoint-object-unions) pattern: ```js flow-check type Action = | {type: 'Upload', data: string} | {type: 'Delete', id: number}; ``` Each object type in the union has a single common field (`type`) which is used to distinguish which object type we are dealing with. We can’t use enum types for this field, because for this mechanism to work, the type of that field must be different in each member of the union, but enum members all have the same type. In the future, we might add the ability for enums to encapsulate additional data besides a key and a primitive value - this would allow us to replace disjoint object unions. #### Guaranteed inlining {#toc-guaranteed-inlining} Flow Enums are designed to allow for inlining (e.g. [member values must be literals](../defining-enums/#toc-literal-member-values), [enums are frozen](../defining-enums/#toc-fixed-at-declaration)), however the inlining itself needs to be part of the build system (whatever you use) rather than Flow itself. While enum member access (e.g. `Status.Active`) can be inlined (other than [symbol enums](../defining-enums/#toc-symbol-enums) which cannot be inlined due to the nature of symbols), usage of its methods (e.g. `Status.cast(x)`) cannot be inlined. --- --- title: Error Suppressions slug: /errors description: "Learn how to suppress Flow's type errors." --- import {SinceVersion, UntilVersion} from '../../components/VersionTags'; Flow reports many different kinds of errors for many common programming mistakes, but not every JavaScript pattern can be understood by Flow. If you are confident your code is correct, and that Flow is erroring too conservatively, you can suppress the error so that Flow does not report it. ### What is a Suppression? {#toc-what-is-a-suppression} A suppression is a special kind of comment that you can place on the line before a type error. It tells Flow not to report that error when checking your code. Suppression comments look like the following: ``` // [] extra text ``` A suppressor can be one of the following: - `$FlowFixMe`: for type errors that you intend to fix later - `$FlowExpectedError`: for a location where you expect Flow to produce a type error (for instance, when performing an invalid type cast).
Removed suppressors - `$FlowIssue` : for a type error that you suspect is an issue with Flow - `$FlowIgnore` : for locations where you want Flow to ignore your code
Note that all of the suppressors behave identically; we simply recommend using them as described here for your own ease of reference. The `` portion of a suppression is required. It specifies which error code the suppression affects. Some examples of suppression comments: ``` // $FlowFixMe[incompatible-type] // $FlowExpectedError[incompatible-type] /* $FlowFixMe[prop-missing] some other text here */ /* $FlowExpectedError[incompatible-type] this is a multi-line comment */ { /* $FlowExpectedError[cannot-resolve-name] this is how you suppress errors inside JSX */ } ``` In order to be a valid suppression comment, there are also some conditions that must be true: - No text can precede the suppressor, or come between the suppressor and the code. For example: `// some text then $FlowFixMe` is not a valid suppression, nor is `// $FlowExpectedError some text [incompatible-type]` or ` //$FlowFixMe [prop-missing]` (note the space here!). - Suppressions must be on the line immediately before the error they suppress, otherwise they will not apply. ### Making Suppressions More Granular with Error Codes {#toc-making-suppressions-more-granular-with-error-codes} :::info Starting from version v0.281, suppressions must have error codes. ::: Suppressible Flow errors will also have an error code associated with them . This code concisely describes the type of issue the error is reporting, and is different between different kinds of errors. In order to prevent suppressions from suppressing different kinds of type errors on the same line (by default suppressions without codes suppress every error on the following line), you can add an error code to your suppression. For example: `// $FlowFixMe[incompatible-type]` would only suppress errors with the `incompatible-type` code. So: ```js flow-check // $FlowFixMe[incompatible-type] 3 as string; ``` would report no errors, but ```js flow-check // $FlowFixMe[prop-missing] 3 as string; ``` would still report a type incompatibility. To suppress multiple error codes on the same line, you can stack suppression comments one after another, and they will all apply to the first non-comment line like so: ```js flow-check let y: number | {x : number} = 1; // $FlowFixMe[incompatible-type] // $FlowFixMe[prop-missing] y.x as string; ``` This will suppress both of the two errors on this line. ### Unsuppressable Errors {#toc-unsuppressable-errors} Certain kinds of errors can be made unsuppressable. For example, to make `react-rule-hook-naming-convention` and `react-rule-hook-conditional` errors unsuppressable, you can add the following to the `[options]` section in `flowconfig`: ``` unsuppressable_error_codes=react-rule-hook-naming-convention unsuppressable_error_codes=react-rule-hook-conditional ``` --- # Source: https://github.com/facebook/flow/blob/main/website/docs/faq.md --- title: FAQ description: Have a question about using Flow? Check here first! slug: /faq --- ## I checked that `foo.bar` is not `null`, but Flow still thinks it is. Why does this happen and how can I fix it? Flow does not keep track of side effects, so any function call may potentially nullify your check. This is called [refinement invalidation](../lang/refinements/#toc-refinement-invalidations). Example: ```js flow-check type Param = { bar: ?string, } function myFunc(foo: Param): string { if (foo.bar) { console.log("checked!"); return foo.bar; // Flow errors. If you remove the console.log, it works } return "default string"; } ``` You can get around this by storing your checked values in local variables: ```js flow-check type Param = { bar: ?string, } function myFunc(foo: Param): string { if (foo.bar) { const bar = foo.bar; console.log("checked!"); return bar; // Ok! } return "default string"; } ``` ## I checked that my value is of type A, so why does Flow still believe it's A | B? Refinement invalidation can also occur variables are updated: ```js flow-check type T = string | number; let x: T = 'hi'; function f() { x = 1; } if (typeof x === 'string') { f(); x as string; } ``` A work around would be to make the variable `const` and refactor your code to avoid the reassignment: ```js flow-check type T = string | number; const x: T = 'hi'; function f(x: T): number { return 1; } if (typeof x === 'string') { const xUpdated = f(x); xUpdated as number; x as string; } ``` ## I'm in a closure and Flow ignores the if check that asserts that `foo.bar` is defined. Why? In the previous section we showed how refinements are lost after a function call. The exact same thing happens within closures, since Flow does not track how your value might change before the closure is called: ```js flow-check const people = [{age: 12}, {age: 18}, {age: 24}]; const oldPerson: {age: ?number} = {age: 70}; if (oldPerson.age) { people.forEach(person => { console.log(`The person is ${person.age} and the old one is ${oldPerson.age}`); }) } ``` The solution here is to move the if check in the `forEach`, or to assign the `age` to an intermediate variable: ```js flow-check const people = [{age: 12}, {age: 18}, {age: 24}]; const oldPerson: {age: ?number} = {age: 70}; if (oldPerson.age) { const age = oldPerson.age; people.forEach(person => { console.log(`The person is ${person.age} and the old one is ${age}`); }) } ``` ## But Flow should understand that this function cannot invalidate this refinement, right? Flow is not [complete](../lang/types-and-expressions/#toc-soundness-and-completeness), so it cannot check all code perfectly. Instead, Flow will make conservative assumptions to try to be sound. ## Why can't I use a function in my if-clause to check the type of a property? Flow doesn't track [refinements](.././lang/refinements/) made in separate function calls: ```js flow-check const add = (first: number, second: number) => first + second; const val: string | number = 1; const isNumber = (x: unknown): boolean => typeof x === 'number'; if (isNumber(val)) { add(val, 2); } ``` However, you can annotate your function with a [type guard](../types/type-guards/) to get this behavior: ```js flow-check const add = (first: number, second: number) => first + second; const val: string | number = 1; // Return annotation updated: const isNumber = (x: unknown): x is number => typeof x === 'number'; if (isNumber(val)) { add(val, 2); } ``` ## Why can't I pass an `Array` to a function that takes an `Array` The function's argument allows `string` values in its array, but in this case Flow prevents the original array from receiving a `number`. Inside the function, you would be able to push a `number` to the argument array, causing the type of the original array to no longer be accurate. You can fix this error by changing the type of the argument to `ReadonlyArray`, making it [covariant](../lang/variance/#toc-covariance). This prevents the function body from pushing anything to the array, allowing it to accept narrower types. As an example, this would not work: ```js flow-check const fn = (arr: Array) => { arr.push(123); // Oops! Array was passed in - now inaccurate return arr; }; const arr: Array = ['abc']; fn(arr); // Error! ``` but with `ReadonlyArray` you can achieve what you were looking for: ```js flow-check const fn = (arr: ReadonlyArray) => { // arr.push(321); NOTE! Since you are using ReadonlyArray<...> you cannot push anything to it return arr; }; const arr: Array = ['abc']; fn(arr); ``` ## Why can't I pass `{a: string}` to a function that takes `{a: string | number}` The function argument allows `string` values in its field, but in this case Flow prevents the original object from having a `number` written to it. Within the body of the function you would be able to mutate the object so that the property `a` would receive a `number`, causing the type of the original object to no longer be accurate. You can fix this error by making the property [covariant](../lang/variance/#toc-covariance) (read-only): `{+a: string | number}`. This prevents the function body from writing to the property, making it safe to pass more restricted types to the function. As an example, this would not work: ```js flow-check const fn = (obj: {a: string | number}) => { obj.a = 123; // Oops! {a: string} was passed in - now inaccurate return obj; }; const object: {a: string} = {a: 'str' }; fn(object); // Error! ``` but with a covariant property you can achieve what you were looking for: ```js flow-check const fn = (obj: {+a: string | number}) => { // obj.a = 123 NOTE! Since you are using covariant {+a: string | number}, you can't mutate it return obj; }; const object: {a: string} = { a: 'str' }; fn(object); ``` ## Why can't I refine a union of objects? There are two potential reasons: 1. You are using inexact objects. 2. You are destructuring the object. When destructuring, Flow loses track of object properties. Broken example: ```js flow-check type Action = | {type: 'A', payload: string} | {type: 'B', payload: number}; // Not OK const fn = ({type, payload}: Action) => { switch (type) { case 'A': return payload.length; // Error! case 'B': return payload + 10; } } ``` Fixed example: ```js flow-check type Action = | {type: 'A', payload: string} | {type: 'B', payload: number}; // OK const fn = (action: Action) => { switch (action.type) { case 'A': return action.payload.length; case 'B': return action.payload + 10; } } ``` ## I got a "Missing type annotation" error. Where does it come from? Flow requires type annotations at module boundaries to make sure it can scale. To read more about that, check out our [blog post](https://medium.com/flow-type/asking-for-required-annotations-64d4f9c1edf8) about that. The most common case you'll encounter is when exporting a function or React component. Flow requires you to annotate inputs. For instance in this example, Flow will complain: ```js flow-check export const add = a => a + 1; ``` The fix here is to add types to the parameters of `add`: ```js flow-check export const add = (a: number): number => a + 1; ``` To see how you can annotate exported React components, check out our docs on [HOCs](../react/hoc/#toc-exporting-wrapped-components). There are other cases where this happens, and they might be harder to understand. You'll get an error like `Missing type annotation for U` For instance, you wrote this code: ```js flow-check const array = ['a', 'b'] export const genericArray = array.map(a => a) ``` Here, Flow will complain on the `export`, asking for a type annotation. Flow wants you to annotate exports returned by a generic function. The type of `Array.prototype.map` is `map(callbackfn: (value: T, index: number, array: Array) => U, thisArg?: any): Array`. The `` corresponds to what is called a [generic](../types/generics/), to express the fact that the type of the function passed to map is linked to the type of the array. Understanding the logic behind generics might be useful, but what you really need to know to make your typings valid is that you need to help Flow to understand the type of `genericArray`. You can do that by annotating the exported constant: ```js flow-check const array = ['a', 'b'] export const genericArray: Array = array.map(a => a) ``` --- # Source: https://github.com/facebook/flow/blob/main/website/docs/getting-started.md --- title: Getting Started slug: /getting-started description: Never used a type system before or just new to Flow? Let's get you up and running in a few minutes. --- Flow is a static type checker for your JavaScript code. It does a lot of work to make you more productive. Making you code faster, smarter, more confidently, and to a bigger scale. Flow checks your code for errors through **static type annotations**. These _types_ allow you to tell Flow how you want your code to work, and Flow will make sure it does work that way. ```js flow-check function square(n: number): number { return n * n; } square("2"); // Error! ``` First step: [install Flow](../install). --- # Source: https://github.com/facebook/flow/blob/main/website/docs/index.md --- title: Documentation description: Guides and references for all you need to know about Flow displayed_sidebar: docsSidebar spug: / --- Guides and references for all you need to know about Flow. import DocCardList from '@theme/DocCardList'; import docsCategories from '../src/js/docs-categories'; --- # Source: https://github.com/facebook/flow/blob/main/website/docs/install.md --- title: Installation slug: /install --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; ## Setup Compiler First you'll need to setup a compiler to strip away Flow types. You can choose between [Babel](http://babeljs.io/) and [flow-remove-types](https://github.com/facebook/flow/tree/master/packages/flow-remove-types). [Babel](http://babeljs.io/) is a compiler for JavaScript code that has support for Flow. Babel will take your Flow code and strip out any type annotations. If you already use Babel in your project, see [using Babel](../tools/babel). First install `@babel/core`, `@babel/cli`, `@babel/preset-flow`, and `babel-plugin-syntax-hermes-parser` with either [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/). ```bash npm2yarn npm install --save-dev @babel/core @babel/cli @babel/preset-flow babel-plugin-syntax-hermes-parser ``` Next you need to create a `.babelrc` file at the root of your project with the `@babel/preset-flow` preset and `babel-plugin-syntax-hermes-parser` plugin. ```json { "presets": ["@babel/preset-flow"], "plugins": ["babel-plugin-syntax-hermes-parser"], } ``` If you then put all your source files in a `src` directory you can compile them to another directory by running: ```bash ./node_modules/.bin/babel src/ -d lib/ ``` You can add this to your `package.json` scripts easily, alongside your `"devDependencies"` on Babel. ```json { "name": "my-project", "main": "lib/index.js", "scripts": { "build": "babel src/ -d lib/", "prepublish": "yarn run build" } } ``` > **Note:** You'll probably want to add a `prepublish` script that runs this > transform as well, so that it runs before you publish your code to the npm > registry. [flow-remove-types](https://github.com/facebook/flow/tree/master/packages/flow-remove-types) is a small CLI tool for stripping Flow type annotations from files. It's a lighter-weight alternative to Babel for projects that don't need everything Babel provides. First install `flow-remove-types` with either [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/). ```bash npm2yarn npm install --save-dev flow-remove-types ``` If you then put all your source files in a `src` directory you can compile them to another directory by running: ```sh ./node_modules/.bin/flow-remove-types src/ -d lib/ ``` You can add this to your `package.json` scripts easily, alongside your `"devDependencies"` on `flow-remove-types`. ```json { "name": "my-project", "main": "lib/index.js", "scripts": { "build": "flow-remove-types src/ -d lib/", "prepublish": "yarn run build" } } ``` > **Note:** You'll probably want to add a `prepublish` script that runs this > transform as well, so that it runs before you publish your code to the npm > registry. ## Setup Flow Flow works best when installed per-project with explicit versioning rather than globally. Luckily, if you're already familiar with `npm` or `yarn`, this process should be pretty familiar! ### Add a `devDependency` on the `flow-bin` npm package ```bash npm2yarn npm install --save-dev flow-bin ``` ### Add a `"flow"` script to your `package.json` ```json { "name": "my-flow-project", "version": "1.0.0", "devDependencies": { "flow-bin": "^0.295.0" }, "scripts": { "flow": "flow" } } ``` ### Run Flow The first time, run: ```bash npm2yarn npm run flow init ``` ``` > my-flow-project@1.0.0 flow /Users/Projects/my-flow-project > flow "init" ``` After running `flow` with `init` the first time, run: ```bash npm2yarn npm run flow ``` ``` > my-flow-project@1.0.0 flow /Users/Projects/my-flow-project > flow No errors! ``` ## Setup ESLint If you use ESLint, you can read [our page on ESLint](../tools/eslint) to set it up to support Flow. --- --- title: Annotation Requirement slug: /lang/annotation-requirement --- > **Note:** As of version 0.199 Flow uses [Local Type Inference](https://medium.com/flow-type/local-type-inference-for-flow-aaa65d071347) as its inference algorithm. The rules in this section reflect the main design features in this inference scheme. Flow tries to avoid requiring type annotation for parts of programs where types can easily be inferred from the immediate context of an expression, variable, parameter, etc. ## Variable declarations Take for example the following variable definition ```js const len = "abc".length; ``` All information necessary to infer the type of `len` is included in the initializer `"abc".length`. Flow will first determine that `"abc"` is a string, and then that the `length` property of a string is a number. The same logic can be applied for all `const`-like initializations. Where things get a little more complicated is when variable initialization spans across multiple statements, for example in ```js flow-check declare const maybeString: ?string; let len; if (typeof maybeString === "string") { len = maybeString.length; } else { len = 0; } ``` Flow can still determine that `len` is a `number`, but in order to do so it looks ahead to multiple initializer statements. See section on [variable declarations](../variables) for details on how various initializer patterns determine the type of a variable, and when an annotation on a variable declaration is necessary. ## Function Parameters Unlike variable declarations, this kind of "lookahead" reasoning cannot be used to determine the type of function parameters. Consider the function ```js function getLength(x) { return x.length; } ``` There are many kinds of `x` on which we could access and return a `length` property: an object with a `length` property, or a string, just to name a few. If later on in the program we had the following calls to `getLength` ```js getLength("abc"); getLength({length: 1}); ``` one possible inference would be that `x` is a `string | { length: number }`. What this implies, however, is that the type of `getLength` is determined by any part of the current program. This kind of global reasoning can lead to surprising action-at-a-distance behavior, and so is avoided. Instead, Flow requires that function parameters are annotated. Failure to provide such a type annotation manifests as a `[missing-local-annot]` error on the parameter `x`, and the body of the function is checked with `x: any`: ```js flow-check function getLength(x) { return x.length; } const n = getLength(1); // no error since getLength's parameter type is 'any' ``` To fix this error, one can simply annotate `x` as ```js flow-check function getLength(x: string) { return x.length; } ``` The same requirement holds for class methods ```js flow-check class WrappedString { data: string; setStringNoAnnotation(x) { this.data = x; } setString(x: string) { this.data = x; } } ``` ## Contextual Typing {#toc-contextual-typing} Function parameters do not always need to be explicitly annotated. In the case of a callback function to a function call, the parameter type can easily be inferred from the immediate context. Consider for example the following code ```js const arr = [0, 1, 2]; const arrPlusOne = arr.find(x => x % 2 === 1); ``` Flow infers that the type of `arr` is `Array`. Combining this with the builtin information for `Array.find`, Flow can determine that the type of `x => x % 2 + 1` needs to be `number => unknown`. This type acts as a *hint* for Flow and provides enough information to determine the type of `x` as `number`. Any attendant annotation can potentially act as a hint to a function parameter, for example ```js flow-check const fn1: (x: number) => number = x => x + 1; ``` However, it is also possible that an annotation cannot be used as a function parameter hint: ```js flow-check const fn2: unknown = x => x + 1; ``` In this example the `unknown` type simply does not include enough information to extract a candidate type for `x`. Flow can infer the types for unannotated parameters even when they are nested within other expressions like objects. For example in in ```js flow-check const fn3: {f: (number) => void} = {f: (x) => {x as string}}; ``` Flow will infer `number` as the type of `x`, and so the cast fails. ## Function Return Types {#toc-function-return-types} Unlike function parameters, a function's return type does not need to be annotated in general. So the above definition of `getLength` won't raise any Flow errors. There are, however, a couple of notable exceptions to this rule. The first one is class methods. If we included to the `WrappedString` class a `getString` method that returns the internal `data` property: ```js flow-check class WrappedString { data: string; getString(x: string) { return this.data; } } ``` Flow would complain that `getString` is missing an annotation on the return. The second exception is recursive definitions. A trivial example of this would be ```js flow-check function foo() { return bar(); } function bar() { return foo(); } ``` The above code raises a `[definition-cycle]` error, which points to the two locations that form a dependency cycle, the two missing return annotations. Adding a return annotation to either function would resolve the issue. Effectively, the requirement on an annotation for method returns is a special-case of the recursive definition restriction. The recursion is possible through access on `this`. ## Generic Calls {#toc-generic-calls} In calls to [generic functions](../../types/generics) the type of the result may depend on the types of the values passed in as arguments. This section discusses how this result is computed, when type arguments are not explicitly provided. Consider for example the definition ```js declare function map( f: (T) => U, array: ReadonlyArray, ): Array; ``` and a potential call with arguments `x => x + 1` and `[1, 2, 3]`: ```js map(x => x + 1, [1, 2, 3]); ``` Here Flow infers that the type of `x` is `number`. Some other common examples of generic calls are calling the constructor of the generic [`Set` class](https://github.com/facebook/flow/blob/82f88520f2bfe0fa13748b5ead711432941f4cb9/lib/core.js#L1799-L1801) or calling `useState` from the React library: ```js flow-check const set = new Set([1, 2, 3]); import {useState} from 'react'; const [num, setNum] = useState(42); ``` Flow here infers that the type of `set` is `Set`, and that `num` and `setNum` are `number` and `(number) => void`, respectively. ### Computing a Solution Computing the result of a generic call amounts to: 1. coming up with a solution for `T` and `U` that does not contain generic parts, 2. replacing `T` and `U` with the solution in the signature of `map`, and 3. performing a call to this new signature of `map`. This process is designed with two goals in mind: * *Soundness*. The results need to lead to a correct call when we reach step (3). * *Completeness*. The types Flow produces need to be as precise and informative as possible, to ensure that other parts of the program will be successfully checked. Let's see how these two goals come into play in the `map` example from above. Flow detects that `ReadonlyArray` needs to be compatible with the type of `[1, 2, 3]`. It can therefore infer that `T` is `number`. With the knowledge of `T` it can now successfully check `x => x + 1`. The parameter `x` is contextually typed as `number`, and thus the result `x + 1` is also a number. This final constraint allows us to compute `U` as a `number` too. The new signature of `map` after replacing the generic parts with the above solution is ```js (f: (number) => number, array: ReadonlyArray) => Array ``` It is easy to see that the call would be successfully checked. ### Errors during Polymorphic Calls If the above process goes on smoothly, you should not be seeing any errors associated with the call. What happens though when this process fails? There are two reasons why this process could fail: #### Under-constrained Type Parameters There are cases where Flow might not have enough information to decide the type of a type parameter. Let's examine again a call to the builtin generic [`Set` class](https://github.com/facebook/flow/blob/82f88520f2bfe0fa13748b5ead711432941f4cb9/lib/core.js#L1799-L1801) constructor, this time without passing any arguments: ```js flow-check const set = new Set(); set.add("abc"); ``` During the call to `new Set`, we are not providing enough information for Flow to determine the type for `T`, even though the subsequent call to `set.add` clearly implies that `T` will be a string. Remember that inference of type arguments is local to the call, so Flow will not attempt to look ahead in later statements to determine this. In the absence of information, Flow would be at liberty to infer *any* type as `T`: `any`, `mixed`, `empty`, etc. This kind of decision is undesirable, as it can lead to surprising results. For example, if we silently decided on `Set` then the call to `set.add("abc")` would fail with an incompatibility between `string` and `empty`, without a clear indication of where the `empty` came from. So instead, in situations like this, you'll get an `[underconstrained-implicit-instantiation]` error. The way to fix this error is by adding a type annotation. There a few potential ways to do this: - Add an annotation at the call-site in one of two ways: * an explicit type argument ```js const set = new Set(); ``` * an annotation on the initialization variable: ```js const set: Set = new Set(); ``` - Add a default type on the type parameter `T` at the definition of the class: ```js declare class SetWithDefault extends ReadonlySet { constructor(iterable?: ?Iterable): void; // more methods ... } ``` In the absence of any type information at the call-site, Flow will use the default type of `T` as the inferred type argument: ```js const defaultSet = new SetWithDefault(); // defaultSet is SetWithDefault ``` #### Incompatibility Errors Even when Flow manages to infer non-generic types for the type parameters in a generic call, these types might still lead to incompatibilities either in the current call or in code later on. For example, if we had the following call to `map`: ```js flow-check declare function map(f: (T) => U, array: ReadonlyArray): Array; map(x => x + 1, [{}]); ``` Flow will infer `T` as `{}`, and therefore type `x` as `{}`. This will cause an error when checking the arrow function since the `+` operation is not allowed on objects. Finally, a common source of errors is the case where the inferred type in a generic call is correct for the call itself, but not indicative of the expected use later in the code. For example, consider ```js flow-check import {useState} from 'react'; const [str, setStr] = useState(""); declare const maybeString: ?string; setStr(maybeString); ``` Passing the string `""` to the call to `useState` makes Flow infer `string` as the type of the state. So `setStr` will also expect a `string` as input when called later on, and therefore passing a `?string` will be an error. Again, to fix this error it suffices to annotate the expected "wider" type of state when calling `useState`: ```js const [str, setStr] = useState(""); ``` ## Empty Array Literals {#toc-empty-array-literals} Empty array literals (`[]`) are handled specially in Flow. You can read about their [behavior and requirements](../../types/arrays/#toc-empty-array-literals). --- --- title: Depth Subtyping slug: /lang/depth-subtyping --- Assume we have two [classes](../../types/classes), which have a subtype relationship using `extends`: ```js flow-check class Person { name: string; } class Employee extends Person { department: string; } ``` It's valid to use an `Employee` instance where a `Person` instance is expected. ```js flow-check class Person { name: string } class Employee extends Person { department: string } const employee: Employee = new Employee(); const person: Person = employee; // OK ``` However, it is not valid to use an object containing an `Employee` instance where an object containing a `Person` instance is expected. ```js flow-check class Person { name: string } class Employee extends Person { department: string } const employee: {who: Employee} = {who: new Employee()}; const person: {who: Person} = employee; // Error ``` This is an error because objects are mutable. The value referenced by the `employee` variable is the same as the value referenced by the `person` variable. ```js person.who = new Person(); ``` If we write into the `who` property of the `person` object, we've also changed the value of `employee.who`, which is explicitly annotated to be an `Employee` instance. If we prevented any code from ever writing a new value to the object through the `person` variable, it would be safe to use the `employee` variable. Flow provides a syntax for this: ```js flow-check class Person { name: string } class Employee extends Person { department: string } const employee: {who: Employee} = {who: new Employee()}; const person: {+who: Person} = employee; // OK person.who = new Person(); // Error! ``` The plus sign `+` indicates that the `who` property is [covariant](../variance/#toc-covariance). Using a covariant property allows us to use objects which have subtype-compatible values for that property. By default, object properties are invariant, which allow both reads and writes, but are more restrictive in the values they accept. Read more about [property variance](../variance/). --- --- title: Lazy Mode slug: /lang/lazy-modes --- By default, the Flow server will typecheck all your code. This way it can answer questions like "are there any Flow errors anywhere in my code". This is very useful for tooling, like a continuous integration hook which prevents code changes which introduce Flow errors. However, sometimes a Flow user might not care about all the code. If they are editing a file `foo.js`, they might only want Flow to typecheck the subset of the repository needed to answer questions about `foo.js`. Since Flow would only check a smaller number of files, this would be faster. This is the motivation behind Flow's lazy mode. ## Classifying Files {#toc-classifying-files} Lazy mode classifes your code into four categories: 1. **Focused files**. These are the files which the user cares about. 2. **Dependent files**. These are the files which depend on the focused files. Changes to the focused files might cause type errors in the dependent files. 3. **Dependency files**. These are the files which are needed in order to typecheck the focused or dependent files. 4. **Unchecked files**. All other files. Lazy mode will still find all the JavaScript files and parse them. But it won't typecheck the unchecked files. ## Choosing Focused Files {#toc-choosing-focused-files} Flow will focus files when they change on disk, using Flow's built-in file watcher ("dfind") or Watchman. So, all files that change while Flow is running will be focused. But what about files that change when Flow is not running? If you're using Git or Mercurial, Flow will ask it for all of the files that have changed since the mergebase with "master" (the common ancestor of the current commit and the master branch). If you're not using "master" (e.g. "main" instead), you can change this with the `file_watcher.mergebase_with` config. If you're working from a clone, you might want to set this to "origin/master" (for Git), which will focus all files that have changed locally, even if you commit to your local "master" branch. The net result is that Flow will find the same errors in lazy mode as in a full check, so long as there are no errors upstream. For example, if your CI ensures that there are no errors in "master," then it's redundant for Flow to check all of the unchanged files for errors that can't exist. ## Using Lazy Mode {#toc-using-lazy-mode} To enable lazy mode, set `lazy_mode=true` in the `.flowconfig`. To start Flow in lazy mode manually, run ```bash flow start --lazy-mode true ``` ## Forcing Flow to Treat a File as Focused {#toc-forcing-flow-to-treat-a-file-as-focused} You can force Flow to treat one or more files as focused from the CLI. ```bash flow force-recheck --focus path/to/A.js path/to/B.js ``` --- --- title: Nominal & Structural Typing slug: /lang/nominal-structural --- A static type checker can use either the name (nominal typing) or the structure (structural typing) of types when comparing them against other types (like when checking if one is a [subtype](../subtypes) of another). ## Nominal typing {#toc-nominal-typing} Languages like C++, Java, and Swift have primarily nominal type systems. ```js // Pseudo code: nominal system class Foo { method(input: string) { /* ... */ } } class Bar { method(input: string) { /* ... */ } } let foo: Foo = new Bar(); // Error! ``` In this pseudo-code example, the nominal type system errors even though both classes have a method of the same name and type. This is because the name (and declaration location) of the classes is different. ## Structural typing {#toc-structural-typing} Languages like Go and Elm have primarily structural type systems. ```js // Pseudo code: structural system class Foo { method(input: string) { /* ... */ } } class Bar { method(input: string) { /* ... */ } } let foo: Foo = new Bar(); // Works! ``` In this pseudo-code example, the structural type system allows a `Bar` to be used as a `Foo`, since both classes have methods and fields of the same name and type. If the shape of the classes differ however, then a structural system would produce an error: ```js // Pseudo code class Foo { method(input: string) { /* ... */ } } class Bar { method(input: number) { /* ... */ } } let foo: Foo = new Bar(); // Error! ``` We've demonstrated both nominal and structural typing of classes, but there are also other complex types like objects and functions which can also be either nominally or structurally compared. Additionally, a type system may have aspects of both structural and nominal systems. ## In Flow Flow uses structural typing for objects and functions, but nominal typing for classes. ### Functions are structurally typed {#toc-functions-are-structurally-typed} When comparing a [function type](../../types/functions) with a function it must have the same structure in order to be considered valid. ```js flow-check type FuncType = (input: string) => void; function func(input: string) { /* ... */ } let test: FuncType = func; // Works! ``` ### Objects are structurally typed {#toc-objects-are-structurally-typed} When comparing an [object type](../../types/objects) with an object it must have the same structure in order to be considered valid. ```js flow-check type ObjType = {property: string}; let obj = {property: "value"}; let test: ObjType = obj; // Works ``` ### Classes are nominally typed {#toc-classes-are-nominally-typed} When you have two [classes](../../types/classes) with the same structure, they still are not considered equivalent because Flow uses nominal typing for classes. ```js flow-check class Foo { method(input: string) { /* ... */ } } class Bar { method(input: string) { /* ... */ } } let test: Foo = new Bar(); // Error! ``` If you wanted to use a class structurally you could do that using an [interface](../../types/interfaces): ```js flow-check interface Interface { method(value: string): void; }; class Foo { method(input: string) { /* ... */ } } class Bar { method(input: string) { /* ... */ } } let test1: Interface = new Foo(); // Works let test2: Interface = new Bar(); // Works ``` ### Opaque types You can use [opaque types](../../types/opaque-types) to turn a previously structurally typed alias into a nominal one (outside of the file that it is defined). ```js flow-check // A.js export type MyTypeAlias = string; export opaque type MyOpaqueType = string; const x: MyTypeAlias = "hi"; // Works const y: MyOpaqueType = "hi"; // Works ``` In a different file: ```js // B.js import type {MyTypeAlias, MyOpaqueType} from "A.js"; const x: MyTypeAlias = "hi"; // Works const y: MyOpaqueType = "hi"; // Error! `MyOpaqueType` is not interchangeable with `string` // ^^^^ Cannot assign "hi" to y because string is incompatible with MyOpaqueType ``` ### Flow Enums [Flow Enums](../../enums) do not allow enum members with the same value, but which belong to different enums, to be used interchangeably. ```js flow-check enum A { X = "x", } enum B { X = "x", } const a: A = B.X; // Error! ``` --- --- title: Type Refinements slug: /lang/refinements --- Refinements allow us to narrow the type of a value based on conditional tests. For example, in the function below `value` is a [union](../../types/unions) of `"A"` or `"B"`. ```js flow-check function func(value: "A" | "B") { if (value === "A") { value as "A"; } } ``` Inside of the `if` block we know that value must be `"A"` because that's the only time the if-statement will be true. The ability for a static type checker to be able to tell that the value inside the if statement must be `"A"` is known as a refinement. Next we'll add an `else` block to our if statement. ```js flow-check function func(value: "A" | "B") { if (value === "A") { value as "A"; } else { value as "B"; } } ``` Inside of the `else` block we know that value must be `"B"` because it can only be `"A"` or `"B"` and we've removed `"A"` from the possibilities. ## Ways to refine in Flow ### `typeof` checks You can use a `typeof value === ""` check to refine a value to one of the categories supported by the [`typeof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) operator. The `typeof` operator can output `"undefined"`,`"boolean"`, `"number"`, `"bigint"`, `"string"`, `"symbol"`, `"function"`, or `"object"`. Keep in mind that the `typeof` operator will return `"object"` for objects, but also `null` and arrays as well. ```js flow-check function func(value: unknown) { if (typeof value === "string") { value as string; } else if (typeof value === "boolean") { value as boolean; } else if (typeof value === "object") { // `value` could be null, an array, or an object value as null | interface {} | ReadonlyArray; } } ``` To check for `null`, use a `value === null` [equality](#equality-checks) check. ```js flow-check function func(value: unknown) { if (value === null) { value as null; // `value` is null } } ``` To check for [arrays](../../types/arrays), use `Array.isArray`: ```js flow-check function func(value: unknown) { if (Array.isArray(value)) { value as ReadonlyArray; // `value` is an array } } ``` ### Equality checks As shown in the introductory example, you can use an equality check to narrow a value to a specific type. This also applies to equality checks made in `switch` statements. ```js flow-check function func(value: "A" | "B" | "C") { if (value === "A") { value as "A"; } else { value as "B" | "C"; } switch (value) { case "A": value as "A"; break; case "B": value as "B"; break; case "C": value as "C"; break; } } ``` While in general it is not recommended to use `==` in JavaScript, due to the coercions it performs, doing `value == null` (or `value != null`) checks `value` exactly for `null` and `void`. This works well with Flow's [maybe](../../types/maybe) types, which create a union with `null` and `void`. ```js flow-check function func(value: ?string) { if (value != null) { value as string; } else { value as null | void; } } ``` You can refine a union of object types based on a common tag, which we call [disjoint object unions](../../types/unions/#toc-disjoint-object-unions): ```js flow-check type A = {type: "A", s: string}; type B = {type: "B", n: number}; function func(value: A | B) { if (value.type === "A") { // `value` is A value.s as string; // Works } else { // `value` is B value.n as number; // Works } } ``` ### Truthiness checks You can use non-booleans in JavaScript conditionals. `0`, `NaN`, `""`, `null`, and `undefined` will all coerce to `false` (and so are considered "falsey"). Other values will coerce to `true` (and so are considered "truthy"). ```js flow-check function func(value: ?string) { if (value) { value as string; // Works } else { value as null | void; // Error! Could still be the empty string "" } } ``` You can see in the above example why doing a truthy check when your value can be a string or number is not suggested: it is possible to unintentionally check against the `""` or `0`. We created a [Flow lint](../../linting) called [sketchy-null](../../linting/rule-reference/#toc-sketchy-null) to guard against this scenario: ```js flow-check // flowlint sketchy-null:error function func(value: ?string) { if (value) { // Error! } } ``` ### `in` checks You can use the [in](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) operator to check if a property exists on an object (either in its own properties, or up the prototype chain). This can be used to refine a union of objects: ```js flow-check function func(obj: {foo: string, value: boolean} | {bar: string, value: number}) { if ('foo' in obj) { obj.value as boolean; // Works! } else { obj.value as number; // Works! } } ``` This works best on unions of [exact objects](../../types/objects/#exact-and-inexact-object-types), since in the negation we know the property does not exist. We cannot say the same for [inexact objects](../../types/objects/#exact-and-inexact-object-types), [interfaces](../../types/interfaces/), and [instance types](../../types/classes/), since they may have other unknown properties, including the one we are checking. Additionally, [optional properties](../../types/objects/#toc-optional-object-type-properties) may or may not exist, so are not particularly useful to check against. If you want to refine a union of [tuple types](../../types/tuples/) based on whether an element exists, check the [length](../../types/tuples/#length-refinement) property instead of attempting to use `in`. ### `instanceof` checks You can use the [instanceof](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) operator to narrow a value as well. It checks if the supplied constructor's prototype is anywhere in a value's prototype chain. ```js flow-check class A { amaze(): void {} } class B extends A { build(): void {} } function func(value: unknown) { if (value instanceof B) { value.amaze(); // Works value.build(); // Works } if (value instanceof A) { value.amaze(); // Works value.build(); // Error } if (value instanceof Object) { value.toString(); // Works } } ``` ### Assignments Flow follows your control flow and narrows the type of a variable after you have assigned to it. ```js flow-check declare const b: boolean; let x: ?string = b ? "str" : null; x as ?string; x = "hi"; // We know `x` must now be a string after the assignment x as string; // Works ``` ### Type Guards You can create a reusable refinement by defining a function which is a [type guard](../../types/type-guards/). ```js flow-check function nonMaybe(x: ?T): x is T { return x != null; } function func(value: ?string) { if (nonMaybe(value)) { value as string; // Works! } } ``` ## Refinement Invalidations {#toc-refinement-invalidations} It is also possible to invalidate refinements, for example: ```js flow-check function otherFunc() { /* ... */ } function func(value: {prop?: string}) { if (value.prop) { otherFunc(); value.prop.charAt(0); // Error! } } ``` The reason for this is that we don't know that `otherFunc()` hasn't done something to our value. Imagine the following scenario: ```js flow-check const obj: {prop?: string} = {prop: "test"}; function otherFunc() { if (Math.random() > 0.5) { delete obj.prop; } } function func(value: {prop?: string}) { if (value.prop) { otherFunc(); value.prop.charAt(0); // Error! } } func(obj); ``` Inside of `otherFunc()` we sometimes remove `prop`. Flow doesn't know if the `if (value.prop)` check is still true, so it invalidates the refinement. There's a straightforward way to get around this. Store the value before calling another function and use the stored value instead. This way you can prevent the refinement from invalidating. ```js flow-check function otherFunc() { /* ... */ } function func(value: {prop?: string}) { if (value.prop) { const prop = value.prop; otherFunc(); prop.charAt(0); } } ``` --- --- title: Subsets & Subtypes slug: /lang/subtypes --- ## What is a subtype? {#toc-what-is-a-subtype} A type like `number`, `boolean`, or `string` describes a set of possible values. A `number` describes every possible number, so a single number (such as `42`) would be a *subtype* of the `number` type. Conversely, `number` would be a *supertype* of the type `42`. If we want to know whether one type is the subtype of another, we need to look at all the possible values for both types and figure out if the other has a _subset_ of the values. For example, if we had a `TypeA` which described the numbers 1 through 3 (a [union](../../types/unions) of [literal types](../../types/literals)), and a `TypeB` which described the numbers 1 through 5: `TypeA` would be considered a _subtype_ of `TypeB`, because `TypeA` is a subset of `TypeB`. ```js flow-check type TypeA = 1 | 2 | 3; type TypeB = 1 | 2 | 3 | 4 | 5; ``` Consider a `TypeLetters` which described the strings: "A", "B", "C", and a `TypeNumbers` which described the numbers: 1, 2, 3. Neither of them would be a subtype of the other, as they each contain a completely different set of values. ```js flow-check type TypeLetters = "A" | "B" | "C"; type TypeNumbers = 1 | 2 | 3; ``` Finally, if we had a `TypeA` which described the numbers 1 through 3, and a `TypeB` which described the numbers 3 through 5. Neither of them would be a subtype of the other. Even though they both have 3 and describe numbers, they each have some unique items. ```js flow-check type TypeA = 1 | 2 | 3; type TypeB = 3 | 4 | 5; ``` ## When are subtypes used? {#toc-when-are-subtypes-used} Most of the work that Flow does is comparing types against one another. For example, in order to know if you are calling a function correctly, Flow needs to compare the arguments you are passing with the parameters the function expects. This often means figuring out if the value you are passing in is a subtype of the value you are expecting. So if you write a function that expects the numbers 1 through 5, any subtype of that set will be acceptable. ```js flow-check function f(param: 1 | 2 | 3 | 4 | 5) { // ... } declare const oneOrTwo: 1 | 2; // Subset of the input parameters type. declare const fiveOrSix: 5 | 6; // Not a subset of the input parameters type. f(oneOrTwo); // Works! f(fiveOrSix); // Error! ``` ## Subtypes of complex types {#toc-subtypes-of-complex-types} Flow needs to compare more than just sets of primitive values, it also needs to be able to compare objects, functions, and every other type that appears in the language. ### Subtypes of objects {#toc-subtypes-of-objects} You can start to compare two objects by their keys. If one object contains all the keys of another object, then it may be a subtype. For example, if we had an `ObjectA` which contained the key `foo`, and an `ObjectB` which contained the keys `foo` and `bar`. Then it's possible that `ObjectB` is a subtype of `ObjectA`, if `ObjectA` is inexact. ```js flow-check type ObjectA = {foo: string, ...}; type ObjectB = {foo: string, bar: number}; let objectB: ObjectB = {foo: 'test', bar: 42}; let objectA: ObjectA = objectB; // Works! ``` But we also need to compare the types of the values. If both objects had a key `foo` but one was a `number` and the other was a `string`, then one would not be the subtype of the other. ```js flow-check type ObjectA = {foo: string, ...}; type ObjectB = {foo: number, bar: number}; let objectB: ObjectB = { foo: 1, bar: 2 }; let objectA: ObjectA = objectB; // Error! ``` If these values on the object happen to be other objects, we would have to compare those against one another. We need to compare every value recursively until we can decide if we have a subtype or not. ### Subtypes of functions {#toc-subtypes-of-functions} Subtyping rules for functions are more complicated. So far, we've seen that `A` is a subtype of `B` if `B` contains all possible values for `A`. For functions, it's not clear how this relationship would apply. To simplify things, you can think of a function type `A` as being a subtype of a function type `B` if functions of type `A` can be used wherever a function of type `B` is expected. Let's say we have a function type and a few functions. Which of the functions can be used safely in code that expects the given function type? ```js flow-check type FuncType = (1 | 2) => "A" | "B"; declare function f1(1 | 2): "A" | "B" | "C"; declare function f2(1 | null): "A" | "B"; declare function f3(1 | 2 | 3): "A"; f1 as FuncType; // Error f2 as FuncType; // Error f3 as FuncType; // Works! ``` - `f1` can return a value that `FuncType` never does, so code that relies on `FuncType` might not be safe if `f1` is used. Its type is not a subtype of `FuncType`. - `f2` can't handle all the argument values that `FuncType` does, so code that relies on `FuncType` can't safely use `f2`. Its type is also not a subtype of `FuncType`. - `f3` can accept all the argument values that `FuncType` does, and only returns values that `FuncType` does, so its type is a subtype of `FuncType`. In general, the function subtyping rule is this: a function type `B` is a subtype of a function type `A` if and only if `B`'s inputs are a superset of `A`'s, and `B`'s outputs are a subset of `A`'s. The subtype must accept _at least_ the same inputs as its parent, and must return _at most_ the same outputs. The decision of which direction to apply the subtyping rule on inputs and outputs is governed by [variance](../variance), which is the topic of the next section. --- --- title: Type Hierarchy slug: /lang/type-hierarchy --- Types in Flow form a hierarchy based on [subtyping](../subtypes): ```mermaid graph BT unknown -.- any symbol --> unknown null --> unknown maybe["Maybe: ?string"] maybe --> unknown null --> maybe void --> maybe void --> unknown string --> maybe string --> unknown union["Union: number | bigint"] number --> union number --> unknown union --> unknown bigint --> unknown bigint --> union boolean --> unknown true --> boolean false --> boolean empty-interface["interface {}"] --> unknown some-interface["interface {prop: string}"] --> empty-interface someclass["class A {prop: string}"] --> some-interface inexact-empty-obj["Inexact empty object: {...}"] inexact-empty-obj --> empty-interface inexact-some-obj["Inexact object: {prop: string, ...}"] --> inexact-empty-obj inexact-some-obj --> some-interface exact-some-obj["Exact object: {prop: string}"] --> inexact-some-obj exact-empty-obj["Exact empty object: {}"] exact-empty-obj --> inexact-empty-obj roarray-unknown["ReadonlyArray<unknown>"] --> empty-interface inexact-empty-tuple["Inexact empty tuple: [...]"] some-tuple["Tuple: [string, number]"] inexact-empty-tuple --> roarray-unknown some-tuple --> inexact-empty-tuple some-array["Array<string>"] --> roarray-unknown any-func["Function: (...ReadonlyArray<empty>) => unknown"] any-func --> empty-interface some-func["(number) => boolean"] --> any-func some-func2["(string) => string"] --> any-func inter["Intersection: (number => boolean) & (string => string)"] inter --> some-func inter --> some-func2 empty --> inter empty --> null empty --> void empty --> true empty --> false empty --> exact-some-obj empty --> exact-empty-obj empty --> some-tuple empty --> some-array empty --> string empty --> number empty --> bigint empty --> someclass empty --> symbol any-bottom["any"] -.- empty click unknown "../../types/unknown" click any "../../types/any" click any-bottom "../../types/any" click empty "../../types/empty" click boolean "../../types/primitives/#toc-booleans" click number "../../types/primitives/#toc-numbers" click string "../../types/primitives/#toc-strings" click symbol "../../types/primitives/#toc-symbols" click bigint "../../types/primitives/#toc-bigints" click null "../../types/primitives/#toc-null-and-void" click void "../../types/primitives/#toc-null-and-void" click true "../../types/literals" click false "../../types/literals" click union "../../types/unions" click inter "../../types/intersections" click maybe "../../types/maybe" click some-array "../../types/arrays" click roarray-unknown "../../types/arrays/#toc-readonlyarray" click inexact-empty-tuple "../../types/tuples/#inexact-tuples" click some-tuple "../../types/tuples" click someclass "../../types/classes" click empty-interface "../../types/interfaces" click some-interface "../../types/interfaces" click exact-some-obj "../../types/objects" click exact-empty-obj "../../types/objects" click inexact-some-obj "../../types/objects/#exact-and-inexact-object-types" click inexact-empty-obj "../../types/objects/#exact-and-inexact-object-types" click any-func "../../types/functions" click some-func "../../types/functions" click some-func2 "../../types/functions" classDef default fill:#eee, stroke:#000, stroke-width:1px ``` Click on a node to go to the documentation for that type. Types appearing higher in this graph are more general, while those appearing lower are more specific. An arrow pointing from type `A` to type `B` means that `A` is a subtype of `B`. For example, the type `string` is a subtype of `?string`. How can `any` be at both the top and the bottom? Because [it is unsafe](../../types/any/). This is denoted with a dotted line. --- --- title: Types & Expressions slug: /lang/types-and-expressions --- In JavaScript there are many types of values: numbers, strings, booleans, functions, objects, and more. ```js flow-check 1234 as number; "hi" as string; true as boolean; [1, 2] as Array; ({prop: "value"}) as {prop: string}; (function func(s: string) {}) as string => void; ``` These values can be used in many different ways: ```js flow-check 1 + 2; "foo" + "bar"; !true; [1, 2].push(3); const obj = {prop: "s"}; let value = obj.prop; obj.prop = "value"; function func(s: string) {} func("value"); ``` All of these different expressions create a new type which is a result of the types of values and the operations run on them. ```js flow-check let num: number = 1 + 2; let str: string = "foo" + "bar"; ``` In Flow every value and expression has a type. ## Figuring out types statically {#toc-figuring-out-types-statically} Flow needs a way to be able to figure out the type of every expression. But it can't just run your code to figure it out, if it did it would be affected by any issues that your code has. For example, if you created an infinite loop Flow would wait for it to finish forever. Instead, Flow needs to be able to figure out the type of a value by analyzing it without running it (static analysis). It works its way through every known type and starts to figure out what all the expressions around them result in. For example, to figure out the result of the following expression, Flow needs to figure out what its values are first. ```js val1 + val2; ``` If the values are numbers, then the expression results in a number. If the values are strings, then the expression results in a string. There are a number of different possibilities here, so Flow must look up what the values are. If Flow is unable to figure out what the exact type is for each value, Flow must figure out what every possible value is and check to make sure that the code around it will still work with all of the possible types. ## Soundness and Completeness {#toc-soundness-and-completeness} When you run your code, a single expression will only be run with a limited set of values. But still Flow checks _every_ possible value. In this way Flow is checking too many things or _over-approximating_ what will be valid code. By checking every possible value, Flow might catch errors that will not actually occur when the code is run. Flow does this in order to be _"sound"_. In type systems, ***soundness*** is the ability for a type checker to catch every single error that _might_ happen at runtime. This comes at the cost of sometimes catching errors that will not actually happen at runtime. On the flip-side, ***completeness*** is the ability for a type checker to only ever catch errors that _would_ happen at runtime. This comes at the cost of sometimes missing errors that will happen at runtime. In an ideal world, every type checker would be both sound _and_ complete so that it catches _every_ error that _will_ happen at runtime. Flow tries to be as sound and complete as possible. But because JavaScript was not designed around a type system, Flow sometimes has to make a tradeoff. When this happens Flow tends to favor soundness over completeness, ensuring that code doesn't have any bugs. Soundness is fine as long as Flow isn't being too noisy and preventing you from being productive. Sometimes when soundness would get in your way too much, Flow will favor completeness instead. There's only a handful of cases where Flow does this. Other type systems will favor completeness instead, only reporting real errors in favor of possibly missing errors. Unit/Integration testing is an extreme form of this approach. Often this comes at the cost of missing the errors that are the most complicated to find, leaving that part up to the developer. --- --- title: File Signatures (Types-First) slug: /lang/types-first --- Flow checks codebases by processing each file separately in dependency order. For every file containing important typing information for the checking process, a signature needs to be extracted and stored in main memory, to be used for files that depend on it. Flow relies on annotations available at the boundaries of files to build these signatures. We call this requirement of Flow's architecture *Types-First*. The benefit of this architecture is dual: 1. It dramatically improves *performance*, in particular when it comes to rechecks. Suppose we want Flow to check a file `foo.js`, for which it hasn't checked its dependencies yet. Flow extracts the dependency signatures just by looking at the annotations around the exports. This process is mostly syntactic, and therefore much faster than full type inference that legacy versions of Flow (prior to v0.125) used to perform in order to generate signatures. 2. It improves error *reliability*. Inferred types often become complicated, and may lead to errors being reported in downstream files, far away from their actual source. Type annotations at file boundaries of files can help localize such errors, and address them in the file that introduced them. The trade-off for this performance benefit is that exported parts of the code need to be annotated with types, or to be expressions whose type can be trivially inferred (for example numbers and strings). More information on the Types-First architecture can be found in [this post](https://medium.com/flow-type/types-first-a-scalable-new-architecture-for-flow-3d8c7ba1d4eb). ## How to upgrade your codebase to Types-First {#toc-how-to-upgrade-your-codebase-to-types-first} > Note: Types-first has been the default mode since v0.134 and the only available mode since v0.143. No `.flowconfig` options are necessary to enable it since then. In case you're upgrading your codebase from a much earlier version here are some useful tools. ### Upgrade Flow version {#toc-upgrade-flow-version} Types-first mode was officially released with version 0.125, but has been available in *experimental* status as of version 0.102. If you are currently on an older Flow version, you’d have to first upgrade Flow. Using the latest Flow version is the best way to benefit from the performance benefits outlined above. ### Prepare your codebase for Types-First {#toc-prepare-your-codebase-for-types-first} Types-first requires annotations at module boundaries in order to build type signature for files. If these annotations are missing, then a `signature-verification-failure` is raised, and the exported type for the respective part of the code will be `any`. To see what types are missing to make your codebase types-first ready, add the following line to the `[options]` section of the `.flowconfig` file: ``` well_formed_exports=true ``` Consider for example a file `foo.js` that exports a function call to `foo` ```js declare function foo(x: T): T; module.exports = foo(1); ``` The return type of function calls is currently not trivially inferable (due to features like polymorphism, overloading etc.). Their result needs to be annotated and so you’d see the following error: ``` Cannot build a typed interface for this module. You should annotate the exports of this module with types. Cannot determine the type of this call expression. Please provide an annotation, e.g., by adding a type cast around this expression. (`signature-verification-failure`) 4│ module.exports = foo(1); ^^^^^^ ``` To resolve this, you can add an annotation like the following: ```js declare function foo(x: T): T; module.exports = foo(1) as number; ``` > Note: As of version 0.134, types-first is the default mode. This mode automatically enables `well_formed_exports`, so you would see these errors without explicitly setting this flag. It is advisable to set `types_first=false` during this part of the upgrade. #### Seal your intermediate results {#toc-seal-your-intermediate-results} As you make progress adding types to your codebase, you can include directories so that they don’t regress as new code gets committed, and until the entire project has well-formed exports. You can do this by adding lines like the following to your .flowconfig: ``` well_formed_exports.includes=/path/to/directory ``` > Warning: That this is a *substring* check, not a regular expression (for performance reasons). #### A codemod for large codebases {#toc-a-codemod-for-large-codebases} Adding the necessary annotations to large codebases can be quite tedious. To ease this burden, we are providing a codemod based on Flow's inference, that can be used to annotate multiple files in bulk. See [this tutorial](../../cli/annotate-exports/) for more. ### Enable the types-first flag {#toc-enable-the-types-first-flag} Once you have eliminated signature verification errors, you can turn on the types-first mode, by adding the following line to the `[options]` section of the `.flowconfig` file: ``` types_first=true ``` You can also pass `--types-first` to the `flow check` or `flow start` commands. The `well_formed_exports` flag from before is implied by `types_first`. Once this process is completed and types-first has been enabled, you can remove `well_formed_exports`. Unfortunately, it is not possible to enable types-first mode for part of your repo; this switch affects all files managed by the current `.flowconfig`. > Note: The above flags are available in versions of Flow `>=0.102` with the `experimental.` prefix (and prior to v0.128, it used `whitelist` in place of `includes`): ``` experimental.well_formed_exports=true experimental.well_formed_exports.whitelist=/path/to/directory experimental.types_first=true ``` > Note: If you are using a version where types-first is enabled by default (ie. `>=0.134`), make sure you set `types_first=false` in your .flowconfig while running the codemods. ### Deal with newly introduced errors {#toc-deal-with-newly-introduced-errors} Switching between classic and types-first mode may cause some new Flow errors, besides signature-verification failures that we mentioned earlier. These errors are due differences in the way types based on annotations are interpreted, compared to their respective inferred types. Below are some common error patterns and how to overcome them. #### Array tuples treated as regular arrays in exports {#toc-array-tuples-treated-as-regular-arrays-in-exports} In types-first, an array literal in an *export position* ```js module.exports = [e1, e2]; ``` is treated as having type `Array`, where `e1` and `e2` have types `t1` and `t2`, instead of the tuple type `[t1, t2]`. In classic mode, the inferred type encompassed both types at the same time. This might cause errors in importing files that expect for example to find type `t1` in the first position of the import. **Fix:** If a tuple type is expected, then the annotation `[t1, t2]` needs to be explicitly added on the export side. #### Indirect object assignments in exports {#toc-indirect-object-assignments-in-exports} Flow allows the code ```js function foo(): void {} foo.x = () => {}; foo.x.y = 2; module.exports = foo; ``` but in types-first the exported type will be ```plaintext { (): void; x: () => void; } ``` In other words it won’t take into account the update on `y`. **Fix:** To include the update on `y` in the exported type, the export will need to be annotated with the type ```plaintext { (): void; x: { (): void; y: number; }; }; ``` The same holds for more complex assignment patterns like ```js function foo(): void {} Object.assign(foo, { x: 1}); module.exports = foo; ``` where you’ll need to manually annotate the export with `{ (): void; x: number }`, or assignments preceding the function definition ```js foo.x = 1; function foo(): void {} module.exports = foo; ``` Note that in the last example, Flow types-first will pick up the static update if it was after the definition: ```js function foo(): void {} foo.x = 1; module.exports = foo; ``` ### Exported variables with updates {#toc-exported-variables-with-updates} The types-first signature extractor will not pick up subsequent update of an exported let-bound variables. Consider the example ```js let foo: number | string = 1; foo = "blah"; module.exports = foo; ``` In classic mode the exported type would be `string`. In types-first it will be `number | string`, so if downstream typing depends on the more precise type, then you might get some errors. **Fix:** Introduce a new variable on the update and export that one. For example ```js const foo1: number | string = 1; const foo2 = "blah"; module.exports = foo2; ``` --- --- title: Variable Declarations slug: /lang/variables --- import {SinceVersion} from '../../components/VersionTags'; When you are declaring a new variable, you may optionally declare its type. JavaScript has three ways of declaring local variables: - `var` - declares a variable, optionally assigning a value. ([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var)) - `let` - declares a block-scoped variable, optionally assigning a value. ([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let)) - `const` - declares a block-scoped variable, assigning a value that cannot be re-assigned. ([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)) In Flow these fall into two groups: - `let` and `var` - variables that **can** be reassigned. - `const` - variables that **cannot** be reassigned. ```js flow-check var varVariable = 1; let letVariable = 1; const constVariable = 1; varVariable = 2; // Works! letVariable = 2; // Works! constVariable = 2; // Error! ``` ## `const` {#toc-const} Since a `const` variable cannot be re-assigned at a later time it is fairly simple. Flow can either infer the type from the value you are assigning to it or you can provide it with a type. ```js flow-check const foo /* : number */ = 1; const bar: number = 2; ``` ## `var` and `let` {#toc-var-and-let} Since `var` and `let` can be re-assigned, there's a few more rules you'll need to know about. When you provide a type, you will be able to re-assign the value, but it must always be of a compatible type. ```js flow-check let foo: number = 1; foo = 2; // Works! foo = '3'; // Error! ``` When the variable has no annotation, Flow infers a precise type based on their initializer or initial assignment. All subsequent assignments to that variable will be constrained by this type. This section shows some examples of how Flow determines what type an unannotated variable is inferred to have. **If you want a variable to have a different type than what Flow infers for it, you can always add a type annotation to the variable’s declaration. That will override everything discussed in this page!** ### Variables initialized at their declarations {#toc-variables-initialized-at-their-declarations} The common case for unannotated variables is very straightforward: when a variable is declared with an initializer that is not the literal `null`, that variable will from then on have the type of the initializer, and future writes to the variable will be constrained by that type. ```js flow-check import * as React from 'react'; type Props = Readonly<{prop: string}>; declare var x: number; declare var y: number; declare var props: Props; let product = Math.sqrt(x) + y; // `product` has type `number` let Component = ({prop}: Props): React.Node => { return
; }; // `Component` has type`React.ComponentType` let element = ; // `element` has type `React.Element>` /* Let's define a new component */ type OtherProps = Readonly<{...Props, extra_prop: number}>; declare var OtherComponent: OtherProps => React.Node; declare var other_props: OtherProps; /* Any subsequent assignments to `product`, `Component`, or `element` will be * checked against the types that Flow infers for the initializers, and if * conflicting types are assigned, Flow will signal an error. */ product = 'Our new product is...'; Component = ({prop}: OtherProps): React.Node => { return
; }; element = ; ``` If you want these examples to typecheck, and for Flow to realize that different kinds of values can be written to these variables, you must add a type annotation reflecting this more general type to their declarations: ```js let product: number | string = ... let Component: unknown = ... // No good type to represent this! Consider restructuring let element: React.Node = ... ``` ### Variables declared without initializers {#toc-variables-declared-without-initializers} Often variables are declared without initializers. In such cases, Flow will try to choose the "first" assignment or assignments to the variable to define its type. "First" here means both top-to-bottom and nearer-scope to deeper-scope—we’ll try to choose an assignment that happens in the same function scope as the variable’s declaration, and only look inside nested functions if we don’t find any assignments locally: ```js flow-check let topLevelAssigned; function helper() { topLevelAssigned = 42; // Error: `topLevelAssigned` has type `string` } topLevelAssigned = 'Hello world'; // This write determines the var's type topLevelAssigned = true; // Error: `topLevelAssigned` has type `string` ``` If there are two or more possible "first assignments," due to an `if`- or `switch`-statement, they’ll both count—this is one of the few ways that Flow will still infer unions for variable types: ```js flow-check let myNumberOrString; declare var condition: boolean; if (condition) { myNumberOrString = 42; // Determines type } else { myNumberOrString = 'Hello world'; // Determines type } myNumberOrString = 21; // fine, compatible with type myNumberOrString = 'Goodbye'; // fine, compatible with type myNumberOrString = false; // Error: `myNumberOrString` has type `number | string` ``` This only applies when the variable is written to in both branches, however. If only one branch contains a write, that write becomes the type of the variable afterwards (though Flow will still check to make sure that the variable is definitely initialized): ```js flow-check let oneBranchAssigned; declare var condition: boolean; if (condition) { oneBranchAssigned = 'Hello world!'; } oneBranchAssigned.toUpperCase(); // Error: `oneBranchAssigned` may be uninitialized oneBranchAssigned = 42; // Error: `oneBranchAssigned` has type `string` ``` ### Variables initialized to `null` {#toc-variables-initialized-to-null} Finally, the one exception to the general principle that variable’s types are determined by their first assignment(s) is when a variable is initialized as (or whose first assignment is) the literal value `null`. In such cases, the _next_ non-null assignment (using the same rules as above) determines the rest of the variable’s type, and the overall type of the variable becomes a union of `null` and the type of the subsequent assignment. This supports the common pattern where a variable starts off as `null` before getting assigned by a value of some other type: ```js flow-check function findIDValue(dict: {[key: string]: T}): T { let idVal = null; // initialized as `null` for (const key in dict) { if (key === 'ID') { idVal = dict[key]; // Infer that `idVal` has type `null | T` } } if (idVal === null) { throw new Error('No entry for ID!'); } return idVal; } ``` ## Catch variables If a `catch` variable does not have an annotation, its default type is [`any`](../../types/any). You can optionally annotate it with exactly [`unknown`](../../types/unknown) or `any`. E.g. ```js flow-check try { } catch (e: unknown) { if (e instanceof TypeError) { e as TypeError; // OK } else if (e instanceof Error) { e as Error; // OK } else { throw e; } } ``` By using `unknown`, you can improve your safety and Flow [coverage](../../cli/coverage/), at the trade-off of increased runtime checks. You can change the default type of `catch` variables when there is no annotation by setting the [`use_unknown_in_catch_variables`](../../config/options/#toc-use-unknown-in-catch-variables) option to true. --- --- title: Type Variance slug: /lang/variance --- Variance is a topic that comes up fairly often in type systems. It is used to determine how type parameters behave with respect to subtyping. First we'll setup a couple of classes that extend one another. ```js class Noun {} class City extends Noun {} class SanFrancisco extends City {} ``` We saw in the section on [generic types](../../types/generics/#toc-variance-sigils) that it is possible to use variance sigils to describe when a type parameter is used in an output position, when it is used in an input position, and when it is used in either one. Here we'll dive deeper into each one of these cases. ## Covariance {#toc-covariance} Consider for example the type ```js type CovariantOf = { +prop: X; getter(): X; } ``` Here, `X` appears strictly in *output* positions: it is used to read out information from objects `o` of type `CovariantOf`, either through property accesses `o.prop`, or through calls to `o.getter()`. Notably, there is no way to input data through the reference to the object `o`, given that `prop` is a readonly property. When these conditions hold, we can use the sigil `+` to annotate `X` in the definition of `CovariantOf`: ```js type CovariantOf<+X> = { +prop: X; getter(): X; } ``` These conditions have important implications on the way that we can treat an object of type `CovariantOf` with respect to subtyping. As a reminder, subtyping rules help us answer the question: "given some context that expects values of type `T`, is it safe to pass in values of type `S`?" If this is the case, then `S` is a subtype of `T`. Using our `CovariantOf` definition, and given that `City` is a subtype of `Noun`, it is also the case that `CovariantOf` is a subtype of `CovariantOf`. Indeed * it is safe to *read* a property `prop` of type `City` when a property of type `Noun` is expected, and * it is safe to *return* values of type `City` when calling `getter()`, when values of type `Noun` are expected. Combining these two, it will always be safe to use `CovariantOf` whenever a `CovariantOf` is expected. A commonly used example where covariance is used is [`ReadonlyArray`](../../types/arrays/#toc-readonlyarray). Just like with the `prop` property, one cannot use a `ReadonlyArray` reference to write data to an array. This allows more flexible subtyping rules: Flow only needs to prove that `S` is a subtype of `T` to determine that `ReadonlyArray` is also a subtype of `ReadonlyArray`. ## Invariance {#toc-invariance} Let's see what happens if we try to relax the restrictions on the use of `X` and make, for example, `prop` be a read-write property. We arrive at the type definition ```js type NonCovariantOf = { prop: X; getter(): X; }; ``` Let's also declare a variable `nonCovariantCity` of type `NonCovariantOf` ```js declare const nonCovariantCity: NonCovariantOf; ``` Now, it is not safe to consider `nonCovariantCity` as an object of type `NonCovariantOf`. Were we allowed to do this, we could have the following declaration: ```js const nonCovariantNoun: NonCovariantOf = nonCovariantCity; ``` This type permits the following assignment: ```js nonCovariantNoun.prop = new Noun; ``` which would invalidate the original type for `nonCovariantCity` as it would now be storing a `Noun` in its `prop` field. What distinguishes `NonCovariantOf` from the `CovariantOf` definition is that type parameter `X` is used both in input and output positions, as it is being used to both read and write to property `prop`. Such a type parameter is called *invariant* and is the default case of variance, thus requiring no prepending sigil: ```js type InvariantOf = { prop: X; getter(): X; setter(X): void; }; ``` Assuming a variable ```js declare const invariantCity: InvariantOf; ``` it is *not* safe to use `invariantCity` in a context where: - an `InvariantOf` is needed, because we should not be able to write a `Noun` to property `prop`. - an `InvariantOf` is needed, because reading `prop` could return a `City` which may not be `SanFrancisco`. In orther words, `InvariantOf` is neither a subtype of `InvariantOf` nor a subtype of `InvariantOf`. ## Contravariance {#toc-contravariance} When a type parameter is only used in *input* positions, we say that it is used in a *contravariant* way. This means that it only appears in positions through which we write data to the structure. We use the sigil `-` to describe this kind of type parameters: ```js type ContravariantOf<-X> = { -prop: X; setter(X): void; }; ``` Common contravariant positions are write-only properties and "setter" functions. An object of type `ContravariantOf` can be used whenever an object of type `ContravariantOf` is expected, but not when a `ContravariantOf` is. In other words, `ContravariantOf` is a subtype of `ContravariantOf`, but not `ContravariantOf`. This is because it is fine to write `SanFrancisco` into a property that can have any `City` written to, but it is not safe to write just any `Noun`. --- --- title: Width Subtyping slug: /lang/width-subtyping --- It's safe to use an object with "extra" properties in a position that is annotated with a specific set of properties, if that object type is [inexact](../../types/objects/#exact-and-inexact-object-types). ```js flow-check function func(obj: {foo: string, ...}) { // ... } func({ foo: "test", // Works! bar: 42 // Works! }); ``` Within `func`, we know that `obj` has at least a property `foo` and the property access expression `obj.foo` will have type `string`. This is a kind of subtyping commonly referred to as "width subtyping" because a type that is "wider" (i.e., has more properties) is a subtype of a narrower type. So in the following example, `obj2` is a _subtype_ of `obj1`. ```js flow-check let obj1: {foo: string, ...} = {foo: 'test'}; let obj2 = {foo: 'test', bar: 42}; obj2 as {foo: string, ...}; ``` However, it's often useful to know that a property is definitely absent. ```js flow-check function func(obj: {foo: string, ...} | {bar: number, ...}) { if (obj.foo) { obj.foo as string; // Error! } } ``` The above code has a type error because Flow would also allow the call expression `func({foo: 1, bar: 2})`, because `{foo: number, bar: number}` is a subtype of `{bar: number, ...}`, one of the members of the parameter's union type. For cases like this where it's useful to assert the absence of a property, You can use [exact object types](../../types/objects/#exact-and-inexact-object-types). ```js flow-check function func(obj: {foo: string} | {bar: number}) { if (obj.foo) { obj.foo as string; // Works! } } ``` [Exact object types](../../types/objects/#exact-and-inexact-object-types) disable width subtyping, and do not allow additional properties to exist. Using exact object types lets Flow know that no extra properties will exist at runtime, which allows [refinements](../refinements/) to get more specific. --- --- title: Creating Library Definitions slug: /libdefs/creation --- import {SinceVersion} from '../../components/VersionTags'; Before spending the time to write your own libdef, we recommend that you look to see if there is already a libdef for the third-party code that you're addressing. `flow-typed` is a [tool and repository](https://github.com/flowtype/flow-typed/) for sharing common libdefs within the Flow community -- so it's a good way to knock out a good chunk of any public libdefs you might need for your project. However sometimes there isn't a pre-existing libdef or you have third-party code that isn't public and/or you really just need to write a libdef yourself. To do this you'll start by creating a `.js` file for each libdef you're going to write and put them in the `/flow-typed` directory at the root of your project. In these libdef file(s) you'll use a special set of Flow syntax (explained below) to describe the interfaces of the relevant third-party code. ## Declaring A Global Function {#toc-declaring-a-global-function} To declare a global function that should be accessible throughout your project, use the `declare function` syntax in a libdef file: **flow-typed/myLibDef.js** ```js flow-check declare function foo(a: number): string; ``` This tells Flow that any code within the project can reference the `foo` global function, and that the function takes one argument (a `number`) and it returns a `string`. ## Declaring A Global Class {#toc-declaring-a-global-class} To declare a global class that should be accessible throughout your project, use the `declare class` syntax in a libdef file: **flow-typed/myLibDef.js** ```js flow-check declare class URL { constructor(urlStr: string): URL; toString(): string; static compare(url1: URL, url2: URL): boolean; } ``` This tells Flow that any code within the project can reference the `URL` global class. Note that this class definition does not have any implementation details -- it exclusively defines the interface of the class. ## Declaring A Global Variable {#toc-declaring-a-global-variable} To declare a global variable that should be accessible throughout your project, use the `declare var`, `declare let`, or `declare const` syntax in a libdef file: **flow-typed/myLibDef.js** ```js flow-check declare const PI: number; ``` This tells Flow that any code within the project can reference the `PI` global variable -- which, in this case, is a `number`. ## Declaring A Global Type {#toc-declaring-a-global-type} To declare a global type that should be accessible throughout your project, use the `declare type` syntax in a libdef file: **flow-typed/myLibDef.js** ```js flow-check declare type UserID = number; ``` This tells Flow that any code within the project can reference the `UserID` global type -- which, in this case, is just an alias for `number`. ## Declaring A Global Namespace {#toc-declaring-a-global-namespace} A namespace defines a collection of values and types: ```js flow-check declare namespace Foo { declare const bar: string; type Baz = number; } Foo.bar as Foo.Baz; // error ``` To declare a global namespace that should be accessible throughout your project, use the `declare namespace` syntax in a libdef file: **flow-typed/myLibDef.js** ```js flow-check declare namespace Foo { declare const bar: string; type Baz = number; } ``` This tells Flow that any code within the project can reference the `Foo` global namespace. If a declared namespace only contains type declarations, then the namespace itself can only be used in a type context. **flow-typed/myTypeOnlyNamespace.js** ```js flow-check declare namespace TypeOnlyFoo { type Baz = number; } TypeOnlyFoo; // error type T = TypeOnlyFoo.Baz; // ok ``` ## Declaring A Module {#toc-declaring-a-module} Often, third-party code is organized in terms of modules rather than globals. Flow offers two different ways to declare a module. ### Declaring a module in the `@flowtyped` directory {#toc-declaring-a-module-in-at-flowtyped} Since v0.251.0, Flow has added support for easily declaring third-party modules in the `@flowtyped` directory at the root of the project. Before looking into `node_modules` for the module specifier `foo/bar/baz`, Flow will look into `@flowtyped/foo/bar/baz.js.flow` and `@flowtyped/foo/bar/baz/index.js.flow`. For example, if you want to declare the types for `react`, you can do: ```js title="@flowtyped/react.js.flow" export type SetStateFunction = ((S => S) | S) => void; declare export function useState(initial: S): [S, SetStateFunction]; // Other stuff... ``` which will allow you to import these functions and types from `react`: ```js title="foo/bar/baz/my-product-code.jsx" import * as React from 'react'; function MyComponent({onSelect}: {onSelect: React.SetStateFunction}) { const [a, setA] = React.useState(new Set()); return
; } // Other stuff... ``` If you want to declare the types for a scoped package like `@my-company/library-a`, you can do ```js title="@flowtyped/@my-company/library-a.js.flow" declare export const foo: string; declare export const bar: number; ``` If you want to declare the types for a deeply nested module in a package like `react-native/internals/foo`, you can do: ```js title="@flowtyped/react-native/internals/foo.js.flow" declare export const SECRET_INTERNALS_Foo: {...}; ``` This approach is preferable to the approach described [below](#toc-declaring-a-module-globally), because editing these files will not trigger a restart of Flow server. ### Declaring a module in the global namespace {#toc-declaring-a-module-globally} You can also declare modules using the `declare module` syntax: ```js declare module "some-third-party-library" { // This is where we'll list the module's exported interface(s) } ``` 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 [`.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 about the two kinds of modules that Flow supports: CommonJS and ES modules. Flow can handle both CommonJS and ES modules, but there are some relevant differences between the two that need to be considered when using `declare module`. #### Declaring An ES Module {#toc-declaring-an-es-module} [ES modules](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) have two kinds of exports: A **named** export and a **default** export. Flow supports the ability to declare either or both of these kinds of exports within a `declare module` body as follows: ###### Named Exports {#toc-named-exports} **flow-typed/some-es-module.js** ```js declare module "some-es-module" { // Declares a named "concatPath" export declare export function concatPath(dirA: string, dirB: string): string; } ``` Note that you can also declare other things inside the body of the `declare module`, and those things will be scoped to the body of the `declare module` -- **but they will not be exported from the module**: **flow-typed/some-es-module.js** ```js declare module "some-es-module" { // Defines the type of a Path class within this `declare module` body, but // does not export it. It can only be referenced by other things inside the // body of this `declare module` declare class Path { toString(): string; } // Declares a named "concatPath" export which returns an instance of the // `Path` class (defined above) declare export function concatPath(dirA: string, dirB: string): Path; } ``` ###### Default Exports {#toc-default-exports} **flow-typed/some-es-module.js** ```js declare module "some-es-module" { declare class URL { constructor(urlStr: string): URL; toString(): string; static compare(url1: URL, url2: URL): boolean; } // Declares a default export whose type is `typeof URL` declare export default typeof URL; } ``` It is also possible to declare both **named** and **default** exports in the same `declare module` body. #### Declaring A CommonJS Module {#toc-declaring-a-commonjs-module} CommonJS modules have a single value that is exported (the `module.exports` value). To describe the type of this single value within a `declare module` body, you'll use the `declare module.exports` syntax: **flow-typed/some-commonjs-module.js** ```js declare module "some-commonjs-module" { // The export of this module is an object with a "concatPath" method declare module.exports: { concatPath(dirA: string, dirB: string): string; }; } ``` Note that you can also declare other things inside the body of the `declare module`, and those things will be scoped to the body of the `declare module`, **but they will not be exported from the module**: **flow-typed/some-commonjs-module.js** ```js declare module "some-commonjs-module" { // Defines the type of a Path class within this `declare module` body, but // does not export it. It can only be referenced by other things inside the // body of this `declare module` declare class Path { toString(): string; } // The "concatPath" function now returns an instance of the `Path` class // (defined above). declare module.exports: { concatPath(dirA: string, dirB: string): Path }; } ``` NOTE: Because a given module cannot be both an ES module and a CommonJS module, it is an error to mix `declare export [...]` with `declare module.exports: ...` in the same `declare module` body. --- --- title: Library Definitions slug: /libdefs description: Learn how to create and use library definitions for the third-party code your code depends on. --- ## What's a "Library Definition"? {#toc-what-s-a-library-definition} Most real JavaScript programs depend on third-party code and not just code immediately under the control of the project. That means a project using Flow may need to reference outside code that either doesn't have type information or doesn't have accurate and/or precise type information. In order to handle this, Flow supports the concept of a "library definition" (a.k.a. "libdef"). A libdef is a special file that informs Flow about the type signature of some specific third-party module or package of modules that your application uses. If you're familiar with languages that have header files (like `C++`), you can think of libdefs as a similar concept. These special files use the same `.js` extension as normal JS code, but they are placed in a directory called `flow-typed` in the root directory of your project. Placement in this directory tells Flow to interpret them as libdefs rather than normal JS files. > NOTE: Using the `/flow-typed` directory for libdefs is a convention that > enables Flow to JustWork™ out of the box and encourages consistency > across projects that use Flow, but it is also possible to explicitly > configure Flow to look elsewhere for libdefs using the [`[libs]` section > of your `.flowconfig`](../config/libs). You can also learn about [declaration files](../declarations). ## General Best Practices {#toc-general-best-practices} **Try to provide a libdef for each third-party library your project uses.** If a third-party library that has no type information is used by your project, Flow will treat it like any other untyped dependency and mark all of its exports as `any`. Because of this behavior, it is a best practice to find or write libdefs for as many of the third-party libraries that you use as you can. We recommend checking out the `flow-typed` [tool and repository](https://github.com/flow-typed/flow-typed/) , which helps you quickly find and install pre-existing libdefs for your third-party dependencies. --- --- title: Flowlint Comments slug: /linting/flowlint-comments --- You can use `flowlint` comments to specify more granular lint settings within a file. These comments come in three forms: * [flowlint](#toc-flowlint) * [flowlint-line](#toc-flowlint-line) * [flowlint-next-line](#toc-flowlint-next-line) In all forms, whitespace and asterisks between words are ignored, allowing for flexible formatting. ### flowlint {#toc-flowlint} The basic `flowlint` comment takes a comma-delimited list of `rule:severity` pairs and applies those settings for the rest of the source file until overridden. This has three primary purposes: applying settings over a block, applying settings over a file, and applying settings over part of a line. **settings over a block of code:** A pair of `flowlint` comments can be used to apply a certain setting over a block of code. For example, to disable the untyped-type-import lint over a block of type imports would look like this: ```js import type { // flowlint untyped-type-import:off Foo, Bar, Baz, // flowlint untyped-type-import:error } from './untyped.js'; ``` **settings over a file:** A `flowlint` comment doesn't have to have a matching comment to form a block. An unmatched comment simply applies its settings to the rest of the file. You could use this, for example, to suppress all sketchy-null-check lints in a particular file: ```js // flowlint sketchy-null:off ... ``` **settings over part of a line:** The settings applied by `flowlint` start and end right at the comment itself. This means that you can do things like ```js function foo(a: ?boolean, b: ?boolean) { if (/* flowlint sketchy-null-bool:off */a/* flowlint sketchy-null-bool:warn */ && b) { ... } else { ... } } ``` if you want control at an even finer level than you get from the line-based comments. ### flowlint-line {#toc-flowlint-line} A `flowlint-line` comment works similarly to a `flowlint` comment, except it only applies its settings to the current line instead of applying them for the rest of the file. The primary use for `flowlint-line` comments is to suppress a lint on a particular line: ```js function foo(x: ?boolean) { if (x) { // flowlint-line sketchy-null-bool:off ... } else { ... } } ``` ### flowlint-next-line {#toc-flowlint-next-line} `flowlint-next-line` works the same as `flowlint-line`, except it applies its settings to the next line instead of the current line: ```js function foo(x: ?boolean) { // flowlint-next-line sketchy-null-bool:off if (x) { ... } else { ... } } ``` --- --- title: Linting Overview slug: /linting description: Learn how to configure Flow's linter to find potentially harmful code. --- Flow contains a linting framework that can tell you about more than just type errors. This framework is highly configurable in order to show you the information you want and hide the information you don't. ### Configuring Lints in the `.flowconfig` {#toc-configuring-lints-in-the-flowconfig} Lint settings can be specified in the `[lints]` section of the `.flowconfig` as a list of `rule=severity` pairs. These settings apply globally to the entire project. ``` [lints] all=warn untyped-type-import=error sketchy-null-bool=off ``` ### Configuring Lints from the CLI {#toc-configuring-lints-from-the-cli} Lint settings can be specified using the `--lints` flag of a Flow server command as a comma-delimited list of `rule=severity` pairs. These settings apply globally to the entire project. ``` flow start --lints "all=warn, untyped-type-import=error, sketchy-null-bool=off" ``` ### Configuring Lints with Comments {#toc-configuring-lints-with-comments} Lint settings can be specified inside a file using `flowlint` comments. These settings apply to a region of a file, or a single line, or part of a line. For more details see [Flowlint Comments](./flowlint-comments). ```js flow-check // flowlint sketchy-null:error const x: ?number = 0; if (x) {} // Error // flowlint-next-line sketchy-null:off if (x) {} // No Error if (x) {} /* flowlint-line sketchy-null:off */ // No Error // flowlint sketchy-null:off if (x) {} // No Error if (x) {} // No Error ``` ### Lint Settings Precedence {#toc-lint-settings-precedence} Lint settings in `flowlint` comments have the highest priority, followed by lint rules in the `--lints` flag, followed by the `.flowconfig`. This order allows you to use `flowlint` comments for fine-grained linting control, the `--lints` flag for trying out new lint settings, and the `.flowconfig` for stable project-wide settings. Within the `--lints` flag and the `.flowconfig`, rules lower down override rules higher up, allowing you to write things like ``` [lints] # warn on all sketchy-null checks sketchy-null=warn # ... except for booleans sketchy-null-bool=off ``` The lint settings parser is fairly intelligent and will stop you if you write a redundant rule, a rule that gets completely overwritten, or an unused flowlint suppression. This should prevent most accidental misconfigurations of lint rules. ### Severity Levels and Meanings {#toc-severity-levels-and-meanings} **off:** The lint is ignored. Setting a lint to `off` is similar to suppressing a type error with a suppression comment, except with much more granularity. **warn:** Warnings are a new severity level introduced by the linting framework. They are treated differently than errors in a couple of ways: * Warnings don't affect the exit code of Flow. If Flow finds warnings but no errors, it still returns 0. * Warnings aren't shown on the CLI by default, to avoid spew. CLI warnings can be enabled by passing the `--include-warnings` flag to the Flow server or the Flow client, or by setting `include_warnings=true` in the `.flowconfig`. This is good for smaller projects that want to see all project warnings at once. **error:** Lints with severity `error` are treated exactly the same as any other Flow error. --- --- title: Lint Rule Reference slug: /linting/rule-reference --- ### `all` {#toc-all} While `all` isn't technically a lint rule, it's worth mentioning here. `all` sets the default level for lint rules that don't have a level set explicitly. `all` can only occur as the first entry in a `.flowconfig` or as the first rule in a `--lints` flag. It's not allowed in comments at all because it would have different semantics than would be expected. ### `ambiguous-object-type` {#toc-ambiguous-object-type} Triggers when you use object type syntax without explicitly specifying exactness or inexactness. This lint setting is ignored when [`exact_by_default`](../../config/options/#toc-exact-by-default) is set to `false`. ```js flow-check // flowlint ambiguous-object-type:error type A = {x: number}; // Error type B = {x: number, ...} // Ok type C = {| x: number |} // Ok ``` ### `deprecated-type` {#toc-deprecated-type} Triggered on the `bool` type, which is just an alias for `boolean`. Just use `boolean` instead. ```js flow-check // flowlint deprecated-type:error type A = Array; // Error ``` ### `implicit-inexact-object` {#toc-implicit-inexact-object} Like [`ambiguous-object-type`](#toc-ambiguous-object-type), except triggers even when the `exact_by_default` option is set to `false`. ### `nonstrict-import` {#toc-nonstrict-import} Used in conjunction with [Flow Strict](../../strict/). Triggers when importing a non `@flow strict` module. When enabled, dependencies of a `@flow strict` module must also be `@flow strict`. ### `sketchy-null` {#toc-sketchy-null} Triggers when you do an existence check on a value that can be either null/undefined or falsey. For example: ```js flow-check // flowlint sketchy-null:error const x: ?number = 5; if (x) {} // sketchy because x could be either null or 0. const y: number = 5; if (y) {} // not sketchy because y can't be null, only 0. const z: ?{foo: number} = {foo: 5}; if (z) {} // not sketchy, because z can't be falsey, only null/undefined. ``` Setting `sketchy-null` sets the level for all sketchy null checks, but there are more granular rules for particular types. These are: * `sketchy-null-bool` * `sketchy-null-number` * `sketchy-null-string` * `sketchy-null-mixed` * `sketchy-null-bigint` The type-specific variants are useful for specifying that some types of sketchy null checks are acceptable while others should be errors/warnings. For example, if you want to allow boolean sketchy null checks (for the pattern of treating undefined optional booleans as false) but forbid other types of sketchy null checks, you can do so with this `.flowconfig` `[lints]` section: ``` [lints] sketchy-null=warn sketchy-null-bool=off ``` and now ```js function foo (bar: ?bool): void { if (bar) { ... } else { ... } } ``` doesn't report a warning. Suppressing one type of sketchy null check only suppresses that type, so, for example ```js flow-check // flowlint sketchy-null:error, sketchy-null-bool:off const x: ?(number | bool) = 0; if (x) {} ``` would still have a `sketchy-null-number` error on line 3. ### `sketchy-number` {#toc-sketchy-number} Triggers when a `number` is used in a manner which may lead to unexpected results if the value is falsy. Currently, this lint triggers if a `number` appears in: * the left-hand side of an `&&` expression. As a motivating example, consider this common idiom in React: ```js {showFoo && } ``` Here, `showFoo` is a boolean which controls whether or not to display the `` element. If `showFoo` is true, then this evaluates to `{}`. If `showFoo` is false, then this evaluates to `{false}`, which doesn't display anything. Now suppose that instead of a boolean, we have a numerical value representing, say, the number of comments on a post. We want to display a count of the comments, unless there are no comments. We might naively try to do something similar to the boolean case: ```js {count && <>[{count} comments]} ``` If `count` is, say, `5`, then this displays "[5 comments]". However, if `count` is `0`, then this displays "0" instead of displaying nothing. (This problem is unique to `number` because `0` and `NaN` are the only falsy values which React renders with a visible result.) This could be subtly dangerous: if this immediately follows another numerical value, it might appear to the user that we have multiplied that value by 10! Instead, we should do a proper conditional check: ```js {count ? <>[{count} comments] : null} ``` ### `unclear-type` {#toc-unclear-type} Triggers when you use `any`, `Object`, or `Function` as type annotations. These types are unsafe. ```js flow-check // flowlint unclear-type:error declare const a: any; // Error declare const c: Object; // Error declare const d: Function; // Error ``` ### `unnecessary-invariant` {#toc-unnecessary-invariant} Triggers when you use `invariant` to check a condition which we know must be truthy based on the available type information. This is quite conservative: for example, if all we know about the condition is that it is a `boolean`, then the lint will not fire even if the condition must be `true` at runtime. Note that this lint does not trigger when we know a condition is always `false`. It is a common idiom to use `invariant()` or `invariant(false, ...)` to throw in code that should be unreachable. ```js flow-check // flowlint unnecessary-invariant:error declare function invariant(boolean): void; declare const x: Array; // Array is truthy invariant(x); ``` ### `unnecessary-optional-chain` {#toc-unnecessary-optional-chain} Triggers when you use `?.` where it isn't needed. This comes in two main flavors. The first is when the left-hand-side cannot be nullish: ```js flow-check // flowlint unnecessary-optional-chain:error type Foo = { bar: number } declare const foo: Foo; foo?.bar; // Error ``` The second is when the left-hand-side could be nullish, but the short-circuiting behavior of `?.` is sufficient to handle it anyway: ```js flow-check // flowlint unnecessary-optional-chain:error type Foo = { bar: { baz: number } } declare const foo: ?Foo; foo?.bar?.baz; // Error ``` In the second example, the first use of `?.` is valid, since `foo` is potentially nullish, but the second use of `?.` is unnecessary. The left-hand-side of the second `?.` (`foo?.bar`) can only be nullish as a result of `foo` being nullish, and when `foo` is nullish, short-circuiting lets us avoid the second `?.` altogether! ```js foo?.bar.baz; ``` This makes it clear to the reader that `bar` is not a potentially nullish property. ### `unsafe-getters-setters` {#toc-unsafe-getters-setters} Triggers when you use getters or setters. Getters and setters can have side effects and are unsafe. For example: ```js flow-check // flowlint unsafe-getters-setters:error let a = 1; const o = { get a() { return a; }, // Error: unsafe-getters-setters set b(x: number) { a = x; }, // Error: unsafe-getters-setters c: 10, }; ``` ### `untyped-import` {#toc-untyped-import} Triggers when you import from an untyped file. Importing from an untyped file results in those imports being typed as `any`, which is unsafe. ### `untyped-type-import` {#toc-untyped-type-import} Triggers when you import a type from an untyped file. Importing a type from an untyped file results in an `any` alias, which is typically not the intended behavior. Enabling this lint brings extra attention to this case and can help improve Flow coverage of typed files by limiting the spread of implicit `any` types. ### `unused-promise` {#toc-unused-promise} Triggers when a `Promise` is unused. This can be dangerous, because errors are potentially unhandled, and the code may not execute in the desired order. A promise can be "used" by... * `await`ing it * Calling `.then` with a rejection handler (i.e., with two arguments) * Calling `.catch` * Calling `.finally` * Storing it in a variable, passing it to a function, etc. For example: ```js flow-check // flowlint unused-promise:error declare function foo(): Promise; async function bar() { await foo(); // ok foo(); // error, we forgot to await! } function baz() { foo().catch(err => {console.log(err)}); // ok foo(); // error } ``` You can explicitly ignore the promise with the `void` operator (e.g., `void foo();`). Note: As of v0.201.0, this rule subsumed the `unused-promise-in-async-scope` and `unused-promise-in-sync-scope` rules. --- --- title: Match Expressions and Statements description: "match an input value against a series of patterns, which conditionally check the structure of the input and extract values, and either produce an expression (match expressions) or execute a block (match statements)." slug: /match --- *An experimental Flow language feature. See [adoption](#adoption) for how to enable.* `match` an input value against a series of [patterns](./patterns), which conditionally check the structure of the input and extract values, and either produce an expression (`match` expressions) or execute a block (`match` statements). You can [replace `switch` statements](./migration#replacing-switch) using `match`, avoiding the problems associated with `switch` (like fall-through behavior) while gaining benefits like [exhaustiveness checks](#exhaustive-checking) and complex pattern support. You can also [replace nested conditional ternary expressions](./migration#replacing-conditional-ternary-expressions) using `match` expressions, making your code much more readable while gaining the power of `match`. ```js component AgePane( maybeAge?: {type: 'valid', age: number} | {type: 'error', msg: string} ) { return match (maybeAge) { {type: 'valid', const age} if (age < 0) => Age cannot be negative!, {type: 'valid', const age} => Age: {age}, {type: 'error', const msg} => {msg}, undefined => Age is not defined., }; } ``` ## Match Expressions Match expressions allow you to define conditional logic as an expression. They can replace nested conditional ternary expressions. A match expression is made up of its argument and a series of cases, each which define a pattern and an expression body. Each pattern is checked in sequence, and the resulting expression is the one accompanying the matching pattern. The resulting expression is typed as the union of every case expression type. A pattern can be followed by a guard, with the `if ()` syntax. If the pattern matches, the expression in the guard is also executed, and the entire case only matches if the result is truthy. Example structure: ```js const e = match () { => , if () => , => , }; ``` The guard applies to the entire pattern, including ["or" patterns](./patterns#or-patterns), e.g. `1 | 2 if (cond)` will first match if the value is `1 | 2`, and then finally succeed if `cond` is also true. Guarded cases do not count toward [exhaustiveness checks](#exhaustive-checking), since they may or may not match based on the condition. You can initialize two or more variables using a `match`: ```js // Using a tuple: const [color, size] = match (status) { Status.Active => ['green', 2], Status.Paused => ['yellow', 1], Status.Off => ['red', 0], }; // Using an object (especially useful for more than two variables): const {color, size} = match (status) { Status.Active => {color: 'green', size: 2}, Status.Paused => {color: 'yellow', size: 1}, Status.Off => {color: 'red', size: 0}, }; ``` Match expressions cannot be used in an expression statement position, as that is reserved for match statements. ```js match () {} // This is a match statement, not a match expression ``` If no pattern matches, Flow will error due to a non-exhaustive match, and an exception will be thrown at runtime. You can use a [wildcard](./patterns#wildcard-patterns) (`_`) or [variable declaration pattern](./patterns#variable-declaration-patterns) (`const x`) as the last case of a match to catch all remaining possible matches. To throw an exception in a `match` expression case body you can't use `throw` as it is a statement, and `match` expressions require expression bodies. Instead, you can use `invariant(false, )`, which Flow understands will always throw (with the supplied message). Match expression case bodies do not yet support usage of `yield`, `yield*`, or `await`. Unlike match expressions, [match statements](#match-statements) do support these keywords. *Fine print:* The opening brace `{` is required to be on the same line as the match argument `match ()`. This way, we can introduce this feature in a way that is backwards compatible with all existing syntax: `match(x);` is still a call to a function called `match`. Prettier will automatically format match expressions in this way. ## Match Statements Match statements can replace `switch` statements or chained `if`\-`else` statements. Similar to match expressions, they have an argument and a series of cases. The difference is each case body is a block (i.e. `{ ...statements... }`) instead of an expression, and the construct is a statement so it does not result in a value. No `break` needed: the cases don’t fall\-through (but you can still combine multiple patterns using ["or" patterns](./patterns#or-patterns) `|`). Example structure: ```js match () { => { ; } if () => { ; } => { ; } } ``` *Fine print:* Like match expressions, the opening brace `{` is required to be on the same line as the match argument `match ()`. ## Exhaustive Checking `match` requires that you have considered all cases of the input. If you don't, Flow will error and tell you what patterns you could add to make the match exhaustive: ```js flow-check declare const tab: 'home' | 'details' | 'settings'; match (tab) { // ERROR 'home' => {} 'settings' => {} } ``` Checks on [disjoint object unions](../types/unions#toc-disjoint-object-unions) are supported. ```js flow-check declare const result: {type: 'ok', value: number} | {type: 'error'}; match (result) { // ERROR {type: 'error'} => {} } ``` It even works for nested structures: ```js flow-check function getStyle( align: 'start' | 'end', position: 'above' | 'below', ) { return match ([align, position]) { // ERROR ['start', 'above'] => 0, ['start', 'below'] => 1, ['end', 'above'] => 2, }; } ``` Flow will also error if a pattern is unused: ```js flow-check declare const tab: 'home' | 'details' | 'settings'; match (tab) { 'home' => {} 'details' => {} 'settings' => {} 'invalid' => {} // ERROR } ``` ## More Learn more about [match patterns](./patterns), including primitive value patterns, array and object patterns, variable declaration patterns, and “or” and “as” patterns. You can also [migrate from existing patterns](./migration) like `switch` or conditional ternary expressions. ## Adoption * Flow: 0.274.1+ with option: `experimental.pattern_matching=true` * Babel: use the [babel-plugin-syntax-hermes-parser](https://www.npmjs.com/package/babel-plugin-syntax-hermes-parser) plugin version 0.29+, see our [Babel guide](../tools/babel) for more details. * ESLint: use [hermes-eslint](https://www.npmjs.com/package/hermes-eslint) plugin version 0.29+, see our [ESLint guide](../tools/eslint) for more details. --- --- title: Migration from existing patterns description: "You can migrate from switch statements and conditional expressions to match expressions and statements" slug: /match/migration --- ## Replacing `switch` You can turn a `switch` into either a match statement or a match expression, depending on its usage. If you are using an IDE, you can use the “Refactor `switch` to `match`” refactoring code-action to do most of the below. To activate, the `switch` needs the following properties: * Every case of the switch must end with a `break`, `return`, or `throw`, except the last case. * If there is a `default`, it must be the last case. * The `case` test must be convertible to a match pattern. * If there is a `let` or `const` in the case body, it must be wrapped in a block. And the caveats for the resulting match: * It may contain other `break`s (other than the last one that was removed) that will be a parse error and you will have to figure out what to do with that. * It may not be exhaustively checked, or identifier patterns may not be valid (e.g. just typed as `string`). You will get new errors you will have to resolve. ### To match statement Most `switch` statements can be turned into match statements: * Replace `switch` with `match` * Delete the `case` * Replace the colon `:` after the case test with an arrow `=>` * Wrap the case body in a block `{ ... }` * Remove the `break;` * If multiple cases share a body, use an ["or" pattern](../patterns#or-patterns) `|` * Replace the `default` with a [wildcard](../patterns#wildcard-patterns) `_` ```js // Before switch (action) { case 'delete': case 'remove': data.pop(); break; case 'add': data.push(1); break; default: show(data); } // After match (action) { 'delete' | 'remove' => { data.pop(); } 'add' => { data.push(1); } _ => { show(data); } } ``` If you are depending on the fallthrough behavior of `switch` cases when not using `break` (other than the simple case where the body is completely shared), then you will likely have to refactor your case body code into a function which is called. ### To match expression If every case of your `switch` has a body that contains a single `return` or a single assignment, then you can turn your `switch` into a match expression. For the `return` case, make the same changes as in the [to match statement](#to-match-statement) section, except: * Replace each case body with only the expression being returned, and delete the `return`, and don't use braces for the `case` body * Separate each case with a comma `,` * Return the entire match expression ```js flow-check // Before function getSizeBefore(imageSize: 'small' | 'medium' | 'large') { switch (imageSize) { case 'small': return 50; case 'medium': return 100; case 'large': return 200; }; } // After function getSizeAfter(imageSize: 'small' | 'medium' | 'large') { return match (imageSize) { 'small' => 50, 'medium' => 100, 'large' => 200, }; } ``` For the assignment case, make the same changes as in the [to match statement](#to-match-statement) section, except: * Replace each case body with only the expression being assigned, and don't use braces for the `case` body * Separate each case with a comma `,` * Assign the entire match expression to the variable * If you no longer re-assign the variable, you can change it to a `const` ```js // Before let colorSchemeStyles; switch (colorScheme) { case 'darker': colorSchemeStyles = colorSchemeDarker; break; case 'light': colorSchemeStyles = colorSchemeLight; break; case 'unset': colorSchemeStyles = colorSchemeDefault; break; } // After const colorSchemeStyles = match (colorScheme) { 'darker' => colorSchemeDarker, 'light' => colorSchemeLight, 'unset' => colorSchemeDefault, }; ``` You can replace multiple assignments with a single match expression: ```js // Before let color; let size; switch (status) { case Status.Active: color = 'green'; size = 2; break; case Status.Paused: color = 'yellow'; size = 1; break; case Status.Off: color = 'red'; size = 0; break; } // After (using a tuple): const [color, size] = match (status) { Status.Active => ['green', 2], Status.Paused => ['yellow', 1], Status.Off => ['red', 0], }; // After (using an object): const {color, size} = match (status) { Status.Active => {color: 'green', size: 2}, Status.Paused => {color: 'yellow', size: 1}, Status.Off => {color: 'red', size: 0}, }; ``` Using an object is more verbose, but may be more readable, especially if dealing with more than two variables. ## Replacing conditional ternary expressions You can replace most conditional expressions `cond ? x : y` with match expressions. This is particularly useful for complex or nested conditional expressions. For example: ```js flow-check declare const obj: | {type: 'a', foo: number} | {type: 'b', bar: string} | null; // Before const a = obj === null ? 0 : obj.type === 'a' ? obj.foo : obj.bar.length; // After const b = match (obj) { {type: 'a', const foo} => foo, {type: 'b', const bar} => bar.length, null => 0, }; ``` ## Dealing with disjoint object unions [Disjoint object unions](../../types/unions#toc-disjoint-object-unions) are unions of object types with some distinguishing property. In the following example, that would be the `type` property: ```js flow-check type Result = {type: 'ok', value: number} | {type: 'error', error: Error}; ``` Previous patterns would involve checking the `result.type` property, and then accessing properties off of `result`: ```js flow-check type Result = {type: 'ok', value: number} | {type: 'error', error: Error}; declare const result: Result; switch (result.type) { case 'ok': console.log(result.value); break; case 'error': throw result.error; } ``` With pattern matching you have to change how you think about it. Rather than doing the conditional checks on the `type` property, you do it on the object itself, and destructure what you need right in the pattern: ```js flow-check type Result = {type: 'ok', value: number} | {type: 'error', error: Error}; declare const result: Result; match (result) { {type: 'ok', const value} => { console.log(value); } {type: 'error', const error} => { throw error; } } ``` If you need to pass in the refined object type itself, you can use an `as` pattern on the object pattern: ```js flow-check type OK = {type: 'ok', value: number}; type Err = {type: 'error', error: Error} type Result = OK | Err; declare const result: Result; match (result) { {type: 'ok', const value} => { console.log(value); } {type: 'error', ...} as err => { // Using `as` throw processError(err); } } declare function processError(err: Err): Error; ``` If you don't need the `type` property included, you could also use an [object rest pattern](../patterns#object-patterns): ```js flow-check type Result = {type: 'ok', value: number} | {type: 'error', error: Error}; declare const result: Result; match (result) { {type: 'ok', const value} => { console.log(value); } {type: 'error', ...const err} => { // Using object rest throw processError(err); } } declare function processError(err: {error: Error}): Error; ``` --- --- title: Match Patterns description: "Match patterns both define a condition that must be matched, and new variables that are extracted (like destructuring)." slug: /match/patterns --- Match patterns both define a condition that must be matched, and new variables that are extracted (like destructuring). ## Primitive value patterns Primitive value patterns include string literals (e.g. `'light'`), number literals (e.g. `42`), BigInt literals (e.g. `10n`), boolean literals (e.g. `true`), `null`, and `undefined`. You can use variables (e.g. `name`) or property accesses (e.g. `Status.Active`) which are either typed as a [literal type](../../types/literals), or a [Flow Enum](../../enums) member. Using variables that are a general type like `string` or `number` is not allowed for match patterns \- they must be a literal type like `'light'`. You can add a type annotation or [`as const`](../../types/const-expression/) to your string value to type it with a literal type. Computed properties in match patterns only allow literals like `foo['bar']` or `foo[2]`. The identifier `_` is special cased for “Wildcard patterns”, if you want to match against a value with that name, rename it to something else first. If you want to create a new variable, take a look at “variable declaration patterns” below \- it is done by doing `const x`. You can use a number literal prefixed with `+` or `-`, or BigInt literals prefixed with `-` (`+` on a BigInt is an error in JS). `+0` and `-0` are not allowed (Flow doesn’t differentiate these type-wise from `0`). `NaN` is special-cased, since `NaN === NaN` is always `false`. It is matched using `Number.isNaN`. Other types of expressions are not supported. To match against an arbitrary expression (which has a literal type), first assign it to a variable, and then match against that variable. Example: ```js match (x) { 1 => {} 'foo' => {} null => {} -1 => {} foo => {} bar.baz => {} bar['bort'] => {} xs[2] => {} } ``` Flow will never output an “unused pattern” error for the `undefined` pattern, so you can always add it even if the input type does not contain `void`. This is to cover the case where Flow does not compute a type that is 100% accurate to the runtime value (for example, from indexed access of an array past its length). At runtime, these checks are done using triple equals `===`. ## Wildcard patterns Wildcard patterns, which are a single underscore `_`, match everything. If you want to match against the value of a variable named `_`, assign it to a different name first. If part of your input type cannot be matched exhaustively (e.g. `string`), then the `match` will require a wildcard. Example: ```js match (x) { _ => {} } ``` ## Variable declaration patterns Variable declaration patterns, like `const name`, take whatever value is at that position and assign it to a new variable. Conditional check wise, they act like a wildcard and match everything. Example: ```js const e = match (x) { const x => x, }; ``` While `let` variables are also supported by the runtime, these are a type error for now and only `const` variables are allowed. If you have a use case, please share it with the team. `var` is not supported. ## Object patterns Object patterns match object values with the same structure. For example, the pattern `{type: 'light', num: 42}` matches objects which have the property `type` with value `'light'`, and a `num` property with value `42`. If the object value has additional unlisted properties, or is inexact, you need to make your pattern inexact using `...`, for example `{type: 'light', num: 42, ...}`. Like destructuring, a variable declaration pattern nested inside an object pattern creates a new variable with the value of that property. E.g. `match (arg) { {prop: const x} => x }` will initialize `x` with the value `arg.prop`. You can use object rest to gather the rest of the object’s own properties: `{foo: 1, ...const rest}`. Doing just `{name}` is ambiguous \- it could mean `{name: name}` (matching against the value of variable `name`) or `{name: const name}` (extracting the property’s value as a new variable called `name`), so it’s not allowed. If you want a shorthand for creating new variables, you can use `{const name}` to mean `{name: const name}`. If you have a property with either a wildcard or variable declaration pattern, e.g. `{foo: _}` or `{foo: const x}`, it is checked that the property is [in](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) the object (checks own and non-own properties). When checking objects with optional properties, in order to make the check exhaustive you must include a pattern that doesn’t include the optional properties. For example, for `{name: string, age?: number}`, if you first match with the pattern `{name: _, age: _}`, you still need to match with the pattern `{name: _, ...}` in order to handle the cases where the `age` property doesn’t exist. Property names can be identifiers (e.g. `foo: pattern`), string literals (e.g. `'foo': )`, or number literals (e.g. `2: `). Repeated object keys are banned, and BigInts are not supported as object keys (Flow doesn’t yet support them). Example: ```js const e = match (x) { {foo: 1, bar: const a} => a, {const baz} => baz, {foo: 2, ...const rest} => rest, }; ``` [Getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) are also not supported \- at runtime they will be evaluated multiple times, once for each conditional check done against them. Flow doesn’t support getters anyway. ## Array patterns Array patterns match both tuple and array values. For example, the pattern `['small', true]` matches array values whose length is `2` and whose elements match the pattern’s elements. If you want a looser length check, you can make the pattern inexact using `...`, for example `['small', true, ...]` will match arrays whose length is `>= 2` and whose first elements match the pattern’s elements. You can match any array or tuple with `[...]`. Like destructuring, a variable declaration pattern nested inside an array pattern creates a new variable with the value of that element. E.g. `match (arg) { [const x] => x }` will initialize `x` with the value `arg[0]`. You can use array rest at the end of the pattern to gather the remaining elements, and check that the length is greater or equal to the pattern length: e.g. `[1, 2, ...const rest]`. Array patterns match values which pass `Array.isArray`, so they won’t match array-like objects that aren’t actually arrays, and won’t match iterables. Use `Array.from` on those types of values first first if you want to match them with array patterns. Example: ```js const e = match (x) { [1, 2] => [], [3, 4, ...] => [], [5, 6, ...const rest] => rest, }; ``` ## “Or” patterns Or patterns allow you to combine multiple patterns using `|`, for example `'active' | 'paused'` will match either string literal. [Variable declaration patterns](#variable-declaration-patterns) inside of "or" patterns are not yet supported. Example: ```js match (x) { 1 | 2 => {} [4] | [5] => {} } ``` ## “As” patterns As patterns both match a pattern and create a new variable. For example, `[_, _] as pair` will first match any arrays whose length is `2`, and then assign that value to a new variable called `pair`. The syntax `as const pair` also works, we’ll decide which one to keep based on feedback. Example: ```js const e = match (x) { // Either one works for now [2, _] as x => x, [1, _] as const x => x, }; ``` --- --- title: Component Syntax slug: /react/component-syntax --- [Components](https://react.dev/learn/your-first-component) are the foundation for building UIs in React. While components are typically expressed using JavaScript functions, Component Syntax provides component primitive values that provide several advantages over function components, like: 1. More elegant syntax with significantly less verbosity and boilerplate than functions 2. Type system support tailored specifically for writing React 3. Better support for [React refs](https://react.dev/learn/manipulating-the-dom-with-refs) ## Basic Usage You can declare a component with Component Syntax similar to how you'd declare a function: ```js flow-check import * as React from 'react'; component Introduction(name: string, age: number) { return

My name is {name} and I am {age} years old

} ``` You can use a component directly in JSX: ``. There are a few important details to notice here: 1. the prop parameter names declared in the Introduction component are the same as the prop names passed to Introduction in JSX 2. the order of the parameters in the declaration does not need to match the order that they are provided in JSX ## Parameters ### String Parameters/Renaming Parameters Components also allow you to rename parameters, which is useful when your parameter name is not a valid JavaScript identifier: ```js flow-check import * as React from 'react'; component RenamedParameter( 'required-renamed' as foo: number, 'optional-renamed' as bar?: number, 'optional-with-default-renamed' as baz?: number = 3, ) { (foo: number); // OK (bar: number | void); // OK (baz: number); // OK return
; } ``` ### Rest Parameters Sometimes you do not want to list out every prop explicitly because you do not intend to reference them individually in your component. This is common when you are writing a component that wraps another and need to pass props from your component to the inner one: ```jsx import * as React from 'react'; import type {Props as StarProps} from './Star'; import Star from './Star'; component BlueStar(...props: StarProps) { return ; } ``` Rest parameters use an object type as an annotation, which means you can use existing type utilities like object spreads and Pick to annotate more complex prop patterns: ```js flow-check import * as React from 'react'; component OtherComponent(foo: string, bar: number) { return foo + bar; } component FancyProps( ...props: { ...React.PropsOf, additionalProp: string, } ) { return ; } ``` ### Optional Parameters and Defaults Components allow you to declare optional parameters and specify defaults: ```js flow-check import * as React from 'react'; component OptionalAndDefaults( color: string = "blue", extraMessage?: string, ) { let message = `My favorite color is ${color}.`; if (extraMessage != null) { message += `\n${extraMessage}`; } return

{message}

} // No error, all of the parameters are optional! ``` ### Destructuring Parameters The `as` operator also allows you to destructure your parameters: ```js flow-check import * as React from 'react'; component Destructuring( config as {color, height}: Readonly<{color: number, height: number}>, ) { return
} ``` Rest parameters can be destructured without using as: ```js flow-check import * as React from 'react'; type Props = Readonly<{ color: string, height: number }>; component DestructuredRest(...{color, height}: Props) { return
} ``` ### Ref Parameters To access refs in components you just need to add a ref parameter. ```js flow-check import * as React from 'react'; component ComponentWithARef(ref: React.RefSetter) { return
; } ``` Behind the scenes Component Syntax will wrap the component in the required [React.forwardRef call](https://react.dev/reference/react/forwardRef) to ensure the component works as expected at runtime. The one restriction for refs is they must be defined as an inline parameter, refs within rest params are not supported. This is due to the need to compile in the `forwardRef` call, for this to work correctly we need to be able to statically determine the ref from the component definition. ## Rules for Components Component Syntax enforces a few restrictions in components to help ensure correctness: 1. The return values must be a subtype of `React.Node`, otherwise React may crash while rendering your component. 2. All branches of a component must end in an explicit return. Even though `undefined` is a valid return value, we've seen many instances where an explicit return would have prevented bugs in production. 3. You cannot use `this` in a component. So these components are invalid: ```js flow-check import * as React from 'react'; component InvalidReturnValue() { return new Object(); // ERROR: Value does not match `React.Node` type } component ImplicitReturn(someCond: boolean) { if (someCond) { return

Hello World!

; } // ERROR: No return in this branch } component UsesThis() { this.foo = 3; // ERROR: Accessing `this` return null; } ``` ## Enable Component Syntax {#toc-enable-component-syntax} In your `.flowconfig`, under the `[options]` heading, add `component_syntax=true`. --- --- title: Component Types slug: /react/component-types --- :::info Component Types are only available in Flow v0.243.0+. If you are on an older version, please use [React.AbstractComponent](../types#toc-react-abstractcomponent) ::: Component Types have syntax similar to our runtime [Component Syntax](../component-syntax) to make it easy to describe the type of a component. Component Types are most useful for writing library definitions. ## Specifying Props To declare a Component Type you can use the `component` keyword and list out the props your component expects. ```js flow-check import * as React from 'react'; type ComponentType = component(numberProp: number, optionalProp?: string); declare const Component: ComponentType; ; // OK! optionalProp is optional ``` Like [Component Syntax](../component-syntax/#rest-parameters), Component Types also accept a rest parameter: ```js import * as React from 'react'; import type {Props as StarProps} from './Star'; import Star from './Star'; type BlueStarType = component(specificProp: string, ...StarProps); ``` Like Component Syntax, you can also declare an inline ref prop (but not in your rest parameter): ```js flow-check import * as React from 'react'; import {useRef} from 'react'; type ComponentWithRef = component(someProp: number, ref: React.RefSetter); declare const Component: ComponentWithRef; component Example() { const ref = useRef(null); return ; } ``` ## Specifying Render Types You can also specify the [Render Type](../render-types) for your component just like you can with [Component Syntax](../render-types/#basic-behavior) ```js flow-check import * as React from 'react'; component Foo() { return null } type ComponentWithRenders = component() renders Foo; declare const Component: ComponentWithRenders; as renders Foo; // OK! ``` ## Polymorphic Component Types You can also write polymorphic Component Types, which is helpful for declaring "transparent" components: ```js flow-check import * as React from 'react'; declare const TransparentComponent: component(children: T) renders T; component Example() { return null } const element: renders Example = ( ); // OK! ``` ## Annotating Components with Component Types Here's how you can describe the type of a Component Syntax component using a Component Type: ```js flow-check import * as React from 'react'; component Foo() { return null } component Example(someProp: number, ref: React.RefSetter) renders Foo { return ; } Example as component(someProp: number, ref: React.RefSetter) renders Foo; // OK! component PolymorphicExample(children: T) renders T { return children; } PolymorphicExample as component(children: T) renders T; // OK! ``` --- --- title: Event Handling slug: /react/events --- The [React docs for handling events](https://react.dev/learn/responding-to-events) show how an event handler can be attached to a React element. To type these event handlers you may use the `SyntheticEvent` types like this: ```js flow-check import {useState} from 'react'; import * as React from 'react'; function MyComponent(): React.Node { const [state, setState] = useState({count: 0}); const handleClick = (event: SyntheticEvent) => { // To access your button instance use `event.currentTarget`. event.currentTarget as HTMLButtonElement; setState(prevState => ({ count: prevState.count + 1, })); }; return (

Count: {state.count}

); } ``` There are also more specific synthetic event types like `SyntheticKeyboardEvent`, `SyntheticMouseEvent`, or `SyntheticTouchEvent`. The `SyntheticEvent` types all take a single type argument: the type of the HTML element the event handler was placed on. If you don't want to add the type of your element instance you can also use `SyntheticEvent` with *no* type arguments like so: `SyntheticEvent<>`. > **Note:** To get the element instance, like `HTMLButtonElement` in the example > above, it is a common mistake to use `event.target` instead of > `event.currentTarget`. The reason you want to use `event.currentTarget` is > that `event.target` may be the wrong element due to [event propagation][]. [event propagation]: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Examples#example_5_event_propagation > **Note:** React uses its own event system so it is important to use the > `SyntheticEvent` types instead of the DOM types such as `Event`, > `KeyboardEvent`, and `MouseEvent`. The `SyntheticEvent` types that React provides and the DOM events they are related to are: - `SyntheticEvent` for [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) - `SyntheticAnimationEvent` for [AnimationEvent](https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent) - `SyntheticCompositionEvent` for [CompositionEvent](https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent) - `SyntheticInputEvent` for [InputEvent](https://developer.mozilla.org/en-US/docs/Web/API/InputEvent) - `SyntheticUIEvent` for [UIEvent](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent) - `SyntheticFocusEvent` for [FocusEvent](https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent) - `SyntheticKeyboardEvent` for [KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent) - `SyntheticMouseEvent` for [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) - `SyntheticDragEvent` for [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent) - `SyntheticWheelEvent` for [WheelEvent](https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent) - `SyntheticTouchEvent` for [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent) - `SyntheticTransitionEvent` for [TransitionEvent](https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent) --- --- title: Function/Class Components slug: /react/function-and-class-components --- Adding Flow types to your [React components](https://react.dev/learn/your-first-component) is incredibly powerful. After typing your component, Flow will statically ensure that you are using the component in the way it was designed to be used. ## Functional Components {#toc-functional-components} Adding Flow types to a functional component is the same as [adding types to a standard function](../../types/functions/). Just create an object type for the props and Flow will ensure that the props passed to the component match up with what is expected. ```js flow-check import React from 'react'; type Props = { foo: number, bar?: string, }; function MyComponent(props: Props) { props.doesNotExist; // Error! You did not define a `doesNotExist` prop. return
{props.bar}
; } ``` ### Adding Default Props to Functional Components {#toc-adding-default-props-to-functional-components} A nice pattern to add default props to functional components is to use [destructuring with default values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment/#default_value). By destructuring the props in the function parameter, you can assign a value to any props that are not passed to the component (or passed with the value `undefined`). ```js flow-check import React from 'react'; type Props = { foo?: number, // foo is optional to pass in. bar: string, // bar is required. }; function MyComponent({foo = 42, bar}: Props) { // Flow knows that foo is not null or undefined const baz = foo + 1; } // And we don't need to include foo. ; ``` ## Class Components {#toc-class-components} To Flowify a [class component](https://react.dev/reference/react/Component#defining-a-class-component), the type of the props can be passed as the first argument to the `React.Component` type. This will have the same effect as adding types to the `props` parameter of a function component. ```js flow-check import React from 'react'; type Props = { foo: number, bar?: string, }; class MyComponent extends React.Component { render(): React.Node { this.props.doesNotExist; // Error! You did not define a `doesNotExist` prop. return
{this.props.bar}
; } } ; ``` Now wherever we use `this.props` in our React component Flow will treat it as the `Props` type we defined. > **Note:** If you don't need to use the `Props` type again you could also > define it inline: `extends React.Component<{ foo: number, bar?: string }>`. `React.Component` is a [generic type](../../types/generics) that takes two type arguments: props and state. The second type argument, `State`, is optional. By default it is `undefined` so you can see in the example above we did not include `State`. We will learn more about state in the next section... ### Adding State {#toc-adding-state} To add a type for state to your React class component: create a new object type, in the example below we name it `State`, and pass it as the second type argument to `React.Component`. ```js flow-check import React from 'react'; type Props = { /* ... */ }; type State = { count: number, }; class MyComponent extends React.Component { state: State = { count: 0, }; componentDidMount() { setInterval(() => { this.setState(prevState => ({ count: prevState.count + 1, })); }, 1000); } render(): React.Node { return
Count: {this.state.count}
; } } ; ``` In the example above we are using a [React `setState()` updater function](https://react.dev/reference/react/Component#setstate) but you could also pass a partial state object to `setState()`. > **Note:** If you don't need to use the `State` type again you could also > define it inline: `extends React.Component<{}, { count: number }>`. ### Using Default Props for Class Components {#toc-using-default-props-for-class-components} React supports the notion of `defaultProps` which you can think of as default function arguments. When you create an element and do not include a prop which has a default then React will substitute that prop with its corresponding value from `defaultProps`. Flow supports this notion as well. To type default props add a `static defaultProps` property to your class. ```js flow-check import React from 'react'; type Props = { foo: number, // foo is required. bar: string, // bar is required. }; class MyComponent extends React.Component { static defaultProps: {foo: number} = { foo: 42, // ...but we have a default prop for foo. }; } // So we don't need to include foo. ``` > **Note:** You don't need to make `foo` nullable in your `Props` type. Flow > will make sure that `foo` is optional if you have a default prop for `foo`. If you add a type annotation to `defaultProps` you can define the type as ```js flow-check type DefaultProps = { foo: number, }; ``` and spread that into the `Props` type: ```js type Props = { ...DefaultProps, bar: string, }; ``` This way you avoid duplicating the properties that happen to have a default value. > **Note:** You can also apply this format of default props to functional components > by adding a `defaultProps` property to a the component function. However, it is generally > simpler to use the destructuring pattern described above. > ```js flow-check > function MyComponent(props: {foo: number}) {} > MyComponent.defaultProps = {foo: 42}; > ``` --- --- title: Higher-order Components slug: /react/hoc --- :::danger Higher-order components are discouraged in modern React code and will not be updated for [Component Syntax](../component-syntax). Consider using a hook to accomplish your task instead. ::: A popular pattern in React is the [higher-order component pattern][], so it's important that we can provide effective types for higher-order components in Flow. If you don't already know what a higher-order component is then make sure to read the [React documentation on higher-order components][] before continuing. [higher-order component pattern]: https://facebook.github.io/react/docs/higher-order-components.html [React documentation on higher-order components]: https://facebook.github.io/react/docs/higher-order-components.html You can make use of the [Component Types](../component-types/) to annotate your higher order components. ### The Trivial HOC {#toc-the-trivial-hoc} Let's start with the simplest HOC: ```js flow-check import * as React from 'react'; function trivialHOC( Component: component(...Config), ): component(...Config) { return Component; } ``` This is a basic template for what your HOCs might look like. At runtime, this HOC doesn't do anything at all. Let's take a look at some more complex examples. ### Injecting Props {#toc-injecting-props} A common use case for higher-order components is to inject a prop. The HOC automatically sets a prop and returns a component which no longer requires that prop. For example, consider a navigation prop. How would one type this? To remove a prop from the config, we can take a component that includes the prop and return a component that does not. It's best to construct these types using object type spread. ```js flow-check import * as React from 'react'; type InjectedProps = {foo: number} function injectProp( Component: component(...{...$Exact, ...InjectedProps}) ): component(...$Exact) { return function WrapperComponent( props: Config, ) { return ; }; } function MyComponent(props: { a: number, b: number, ...InjectedProps, }): React.Node {} const MyEnhancedComponent = injectProp(MyComponent); // We don't need to pass in `foo` even though `MyComponent` requires it: ; // OK // We still require `a` and `b`: ; // ERROR ``` ### Preserving the Instance Type of a Component {#toc-preserving-the-instance-type-of-a-component} Recall that the instance type of a function component is `void`. Our example above wraps a component in a function, so the returned component has the instance type `void`. ```js flow-check import * as React from 'react'; type InjectedProps = {foo: number} function injectProp( Component: component(...{...$Exact, ...InjectedProps}) ): component(...$Exact) { return function WrapperComponent( props: Config, ) { return ; }; } // A class component in this example class MyComponent extends React.Component<{ a: number, b: number, ...InjectedProps, }> {} const MyEnhancedComponent = injectProp(MyComponent); // If we create a ref object for the component, it will never be assigned // an instance of MyComponent! const ref = React.createRef(); // Error, mixed is incompatible with MyComponent. ; ``` We get this error message because component type doesn't declare the `ref` prop, so it is treated as `React.RefSetter`. If we wanted to preserve the instance type of the component, we can use [`React.forwardRef`](https://reactjs.org/docs/forwarding-refs.html): ```js flow-check import * as React from 'react'; type InjectedProps = {foo: number} function injectAndPreserveInstance( Component: component(ref?: React.RefSetter, ...{...$Exact, ...InjectedProps}) ): component(ref?: React.RefSetter, ...$Exact) { return React.forwardRef<$Exact, Instance>((props, ref) => ); } class MyComponent extends React.Component<{ a: number, b: number, ...InjectedProps, }> {} const MyEnhancedComponent = injectAndPreserveInstance(MyComponent); const ref = React.createRef(); // All good! The ref is forwarded. ; ``` ### Exporting Wrapped Components {#toc-exporting-wrapped-components} If you try to export a wrapped component, chances are that you'll run into a missing annotation error: ```js flow-check import * as React from 'react'; function trivialHOC( Component: component(...Config), ): component(...Config) { return Component; } type Props = Readonly<{bar: number, foo?: number}>; function MyComponent({bar, foo = 3}: Props): React.Node {} export const MyEnhancedComponent = trivialHOC(MyComponent); // ERROR ``` You can add an annotation to your exported component using component types: ```js flow-check import * as React from 'react'; function trivialHOC( Component: component(...Config), ): component(...Config) { return Component; } type Props = Readonly<{bar: number, foo?: number}>; function MyComponent({bar, foo = 3}: Props): React.Node {} export const MyEnhancedComponent: component(...Props) = trivialHOC(MyComponent); // OK ``` --- --- title: Hook Syntax slug: /react/hook-syntax --- Hook Syntax is first-class syntax and typechecking support for React hooks, bringing hooks into the React language as their own entities that are syntactically and semantically distinct from regular functions, and using Flow to enforce that the [Rules of React](https://react.dev/reference/rules) aren’t violated. ## Basic Usage The primary difference between writing a function and a hook is the `hook` keyword: ```js flow-check import {useState, useEffect} from 'react'; hook useOnlineStatus(initial: boolean): boolean { const [isOnline, setIsOnline] = useState(initial); useEffect(() => { // ... }, []); return isOnline; } ``` Hooks can be called just like regular functions: ```js flow-check import * as React from 'react'; hook useOnlineStatus(): boolean { return true; } component StatusBar() { const isOnline = useOnlineStatus(); return

{isOnline ? '✅ Online' : '❌ Disconnected'}

; } ``` Hooks can be exported just like normal functions: ```js flow-check export hook useNamedExportedHook(): boolean { return true; } export default hook useDefaultExportedHook(): boolean { return true; } ``` ## Hook Type Annotations There are a few cases where you might wish to define a value as having the type of a hook. Because function types and hook types aren’t compatible (more on this below!), we also introduce a new syntax for hook type annotations, which is simply the existing function type annotation but preceded by hook. ```js export const useGKOnlineStatus: hook (boolean) => boolean = experiment('show_online_status') ? useOnlineStatus : useAlwaysOnlineStatus ``` ## Enforcing the Rules of React with Hook Syntax With hook syntax, we can now unambiguously distinguish syntactically between hooks and non-hooks. Flow will use this information to enforce a number of the rules of hooks and [Rules of React](https://react.dev/reference/rules) generally. ### Preventing Unsafe Mutation According to the [Rules of React](https://react.dev/reference/rules), refs aren’t allowed to be read from or written to while a component is rendering, and the return value of other hooks (especially `useState``) cannot be safely mutated directly at all. By making Flow aware of hooks as a first-class concept, we can now detect these issues in many cases and raise errors early, rather than depending on testing to uncover them. ```js flow-check import {useState, useEffect, useRef} from 'react'; import * as React from 'react'; component MyComponent() { const ref = useRef(null); const [state, setState] = useState<{ val: number }>({val: 0}); state.val = 42; // Flow error: cannot mutate return value of hook return (
{ref.current /* Flow error: cannot read ref during rendering */}
); } ``` Flow currently prevents component props from being modified within the component. Hook syntax allows us to extend this checking to hooks, and will let us detect and raise errors when illegal mutations occur within hook declarations. ```js flow-check hook useIllegalMutation(values: Array) { values[0] = 42; // Flow error: mutating argument to hook // ... } ``` ### Preventing Conditional Hook Calls [The Rules of Hooks](https://react.dev/reference/rules#rules-of-hooks) prohibit hooks from being called conditionally. This is covered by [React's ESLint plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks), but now Flow will check for these violations too. ```js flow-check hook useOnlineStatus(): boolean { return true; } component StatusBar(shouldShowOnlineStatus: boolean) { if (shouldShowOnlineStatus) { const onlineStatus = useOnlineStatus(); } return null; } ``` ### Preventing Conflation of Hooks and Functions The distinction between hooks and regular functions is reflected in the Flow type system. Because of the different properties that hooks and functions must obey, it’s Flow error to pass a value defined as a hook into a position that expects a function type, and an error to pass a regular JavaScript function into a position that expects a hook. ```js flow-check import {useState, useEffect} from 'react'; hook useMultiplier(x: number): number { const [y, setY] = useState(1); useEffect(() => { setY(0) }) return x * y; } component Mapper(args: Array) { const multArgs = args.map(useMultiplier); return multArgs; } ``` In addition, Flow enforces that callees with hook-like names inside hooks and components are indeed hooks. We also ensure that callees inside of regular function definitions are never hooks. ```js flow-check hook useHook() { return null } function regularJavascript() { const x = useHook(); // Flow error: cannot call a hook outside of a component or hook } component Component() { const renamedHook = useHook; renamedHook(); // Flow error: cannot call a hook whose name does not begin with `use` return null; } ``` --- --- title: Getting Started slug: /react description: Learn how to use Flow to effectively type common and advanced React patterns. --- Developers will often use Flow and React together, so it is important that Flow can effectively type both common and advanced React patterns. This guide will teach you how to use Flow to create safer React applications. In this guide we will assume you know [the React basics](https://react.dev/learn) and focus on adding types for patterns you are already familiar with. We will be using examples based on `react-dom`, but all of these patterns work in other environments like `react-native` as well. ## Setup Flow with React {#toc-setup-flow-with-react} Flow and Babel work well together, so it doesn't take much to adopt Flow as a React user who already uses Babel. If you need to setup Babel with Flow, you can follow [this guide](../tools/babel/). ## Check Out Component Syntax Flow supports a dedicated syntax for writing React components and hooks that we recommend instead of using regular function/class components. Ensure you are set up using our [most up-to-date instructions to configure your toolchain](../install) and then take a look at the [Component Syntax](./component-syntax) and [Hook Syntax](./hook-syntax) docs. ## React Runtimes Flow supports the `@babel/plugin-transform-react-jsx` runtime options required to use JSX without explicitly importing the React namespace. If you are using the new automatic runtime, use this configuration in your `.flowconfig` so that Flow knows to auto-import `jsx`: ```ini [options] react.runtime=automatic ``` --- --- title: Multi-platform Support for React Native slug: /react/multiplatform description: "Flow's support for multiple platforms inside a single React Native codebase" --- :::caution The feature is still experimental. Behaviors might change in the future. ::: ## Benefits {#toc-benefits} React Native supports conditional bundling of files with [platform specific extensions](https://reactnative.dev/docs/platform-specific-code#platform-specific-extensions). For example, if you have different implementations of an Image component for iOS and Android, you can have an `Image.ios.js` file and `Image.android.js` file, and an import of Image can be resolved to either file based on the platform you are targeting. These platform specific files live under the same repository, but it would normally require two flowconfigs to check them like the following setup: ```toml title=.flowconfig ; for ios [ignore] .*\.android\.js$ [options] module.file_ext=.js module.file_ext=.ios.js ``` ```toml title=.flowconfig.android ; for android [ignore] ; Ignore other platform suffixes .*\.ios\.js$ [options] module.file_ext=.js module.file_ext=.android.js ``` Flow's optional React Native multi-platform support allows you to check your entire project with mixed platforms under a single Flow root, so that during the development of a module with both .ios and .android files, you no longer have to run both Flow servers and constantly switch between different servers to see type errors on different platforms. ## Quick Start {#toc-quick-start} You can start by deleting the flowconfig for all other platforms, deleting all the platform specific configs in the only remaining flowconfig, and add the following new lines to the `options` section: ``` experimental.multi_platform=true experimental.multi_platform.extensions=.ios experimental.multi_platform.extensions=.android ``` For example, these are the required changes for the `.flowconfig` example above: ```diff title=.flowconfig [ignore] - .*\.android\.js$ [options] module.file_ext=.js - module.file_ext=.ios.js + experimental.multi_platform=true + experimental.multi_platform.extensions=.ios + experimental.multi_platform.extensions=.android ``` After enabling the new configurations, there will likely be new errors. The sections below explain the additional rules that Flow imposes to check a multiplatform React Native project. ## Common Interface Files {#toc-common-interface-file} Suppose you have a file that imports the `Image` module, but `Image` module has different iOS and Android implementations as follows: ```jsx title=MyReactNativeApp.js import * as React from 'react'; import Image from './Image'; ; ; ``` ```jsx title=Image.ios.js import * as React from 'react'; type Props = { src: string, lazyLoading?: boolean }; export default function Image(props: Props): React.Node { /* ... */ } ``` ```jsx title=Image.android.js import * as React from 'react'; type Props = { src: string, lazyLoading: boolean }; export default class Image extends React.Components { static defaultProps: { lazyLoading: boolean } = { lazyLoading: false }; render(): React.Node { /* ... */ } } ``` When you enabled multiplatform support, you will likely see that error that the `./Image` module cannot be resolved. To fix the error, you need to create a common interface file under the same directory: ### Common Interface File in `.js.flow` {#toc-common-interface-file-in-js-flow} One option is to write a common interface file in `.js.flow`: With [Component Types](../component-types/) ```jsx title=Image.js.flow import * as React from 'react'; type Props = { src: string, lazyLoading?: boolean }; declare const Image: component(...Props); export default Image; ``` With [React.ComponentType](../types#toc-react-componenttype) ```jsx title=Image.js.flow import * as React from 'react'; type Props = { src: string, lazyLoading?: boolean }; declare const Image: React.ComponentType; export default Image; ``` Flow will ensure that the module types of both `Image.ios.js` and `./Image.android.js` are subtype of the module type of `./Image.js.flow`. Flow will also ensure that there exists an implementation for each platform you declared in your `.flowconfig`. ### Common Interface File in `.js` {#toc-common-interface-file-in-js} Sometimes you might target desktop platforms in addition to iOS and Android, and you only have a special implementation for one platform, and all the other platforms will use the fallback implementation in a `.js` file. For example: ```jsx title=Image.js import * as React from 'react'; import DefaultImage from 'react-native/Libraries/Image'; export default DefaultImage; ``` ```jsx title=Image.ios.js import * as React from 'react'; type Props = { src: string, lazyLoading: boolean }; export default function Image(props: Props): React.Node { // Custom implementation to take advantage of some unique iOS capabilities } ``` In this case, Flow will use the `.js` file as the common interface file, and check all other platform-specific implementation files' against the `.js` file. Since the `.js` file is already a fallback implementation, Flow will no longer require that platform-specific implementation files exist for all platforms. --- --- title: Ref Functions slug: /react/refs --- React allows you to grab the instance of an element or component with [refs](https://react.dev/learn/manipulating-the-dom-with-refs). ## Refs in Functional Components {#toc-refs-in-functional-components} Inside a functional component, refs are accessed with the `useRef` hook: ```js flow-check import {useRef} from 'react'; import * as React from 'react'; function MyComponent() { const buttonRef = useRef(null); buttonRef as {current: null | HTMLButtonElement}; // useRef wraps the ref value in an object return ; } ``` Note that `useRef` wraps the ref value in an object with a `current` property. This must be reflected in the type of anything accepting the ref value. ## Refs in Class Components {#toc-refs-in-class-components} Refs in class components are similar to function components. To create one, add a property to your class and assign the result of `React.createRef` to it. ```js flow-check import * as React from 'react'; class MyComponent extends React.Component<{}> { // The `null` here is important because you may not always have the instance. buttonRef: {current: null | HTMLButtonElement}; constructor() { super(); this.buttonRef = React.createRef(); } render(): React.Node { return ; } } ``` One notable difference between `useRef` and `createRef` is that `createRef` does not accept a default value. It will initialize the ref with the value `null`. This is because DOM elements will not exist until the first render of `MyComponent` and so a `null` value must be used. Again, note that the ref value is wrapped in an object with a `current` property. --- --- title: Render Types slug: /react/render-types --- Some component libraries or design systems may want to restrict how components may be composed. For example, a Menu should only ever render MenuItems as children. Render types are a built-in way to support these constraints while still affording users rich flexibility in how they use those components. ## Basic Behavior A component can declare what it renders using the renders keyword: ```js flow-check import * as React from 'react'; component Header(size: string, color: string) { return
} component LargeHeader(color: string) renders Header { return
; // Ok! } ``` When you declare that your component renders some specific element, you can return any component that eventually renders that component in its renders chain: ```js flow-check import * as React from 'react'; component Header(size: string, color: string) { return
} component LargeHeader(color: string) renders Header { return
; } component LargeBlueHeader() renders Header { // You could also use `renders LargeHeader` above return ; } ``` Components can specify props that render specific elements: ```js flow-check import * as React from 'react'; component Header(size: string, color: string, message: string) { return

{message}

; } component Layout(header: renders Header) { return (
{header}
Hi
); } ``` And you can pass an element of either Header, or an element of a component that renders `Header`, to that prop: ```js } />; ``` You cannot pass a component that does not render a header to a render type expecting a header: ```js flow-check import * as React from 'react'; component Footer() { return