codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.

Follow publication

Harden up Node.js with Flow: Part 2

We wrap up this series with editor integration and using third-party libraries.

This is part of a series starting with Harden up Node.js with Flow: Part 1, on using Flow to add the benefits of static typing to Node.js projects.

Editor Integration

Much like eslint, Flow can be integrated into a number of editors / IDEs; enabling some additional helpful features (would go as far as to say critical features). As I am using Atom, I chose to use Nuclide for these features.

Nuclide is a full IDE created by people at Facebook that has support for Flow built-in. It provides a linter, autocomplete and type coverage support, click-to-definition and type description on hover.

— Facebook Open Source Team

First, there is inline flow errors messages. Unfortunately, they only show up when saving; luckily I save often.

It also shows type definitions on hover. Here we can see that foo is a function with signature, (x: ?number) => string, or takes an optional number parameter and returns a string.

In addition, it indicates type coverage. Our earlier example has 100% type coverage (good). But a file with the following code has 55% type coverage (worse).

/* eslint-disable no-console */
// @flow
export default function bar(x) {
if (x) {
// return x; // BROKEN
return x.toString(); // FIXED
}
console.log('test');
return 'default string';
}

In the editor, you can see which lines are contributing to the problem.

Third-Party Libraries

So far we have been using Flow without third-party libraries; they introduce some additional challenges.

If the third-party libraries could be simply Flow annotated, like our source code, things would be trivial, e.g.,

node_modules/mymodule/index.js

// @flow
export default function foo(x: ?number): string {
if (x) {
return x.toString();
}
return 'default string';
}

The problem, however, is that Flow is not universally adopted and even then one does not typically transpile third-party libraries. In this case, one solution is if the module provides both a transpiled format and in the flow annotated format. In my sample module, Node.js will use the transpiled file and Flow will use the flow annotated version.

node_modules/mymodule/index.js

exports = module.exports = function foo(x) {
if (x) {
return x.toString();
}
return 'default string';
}

node_modules/mymodule/index.js.flow

// @flow
export default function foo(x: ?number): string {
if (x) {
return x.toString();
}
return 'default string';
}

The problem, however, is… What to do when the third-party library does not provide flow annotated format files? The answer is to use a library definition file (file in folder named flow-typed and with extension .js; otherwise naming is simply by convention), e.g.,

flow-typed/npm/mymodule_v1.0.x.js

declare module 'mymodule' {
declare module.exports: {
(x: ?number): string
}
}

Flow-Typed

Because we don’t want to write library definitions for others’ third-party libraries there is flow-typed.

The flow-typed repo is a collection of high-quality library definitions, tests to ensure that definitions remain high quality, and tooling to make it as easy as possible to import them into your project.

flow-typed team

Let us first see what happens when we use third-party libraries without a library definition. Let us use Express’ hello-world example.

Because Flow does not know the signatures of the Express library, our code’s type coverage suffers (42%). To resolve this we first install flow-typed, use it to install the appropriate library definitions, and use them in our code. (full example is available).

sudo npm install -g flow-typed

From the project folder we run:

flow-typed install express@4.16.x

note: The available definitions are listed.

This will install the library definition into the file flow-typed/npm/express_v4.16.x.js.

With the library definition installed, Flow reports a number of errors; the first is with the get method call.

While I did not find the error message terribly helpful, I bumbled my way through the downloaded express_v4.16.x.js library definition to the proper syntax; was pretty tangled.

note: It is recommended that you commit the third-party library definitions into into your repository as they are changing rapidly (and not versioned themselves).

index.js

// @flow
/* eslint-disable no-console */
import express from 'express';
import type { $Request, $Response } from 'express';
const app = express();
app.get('/', (req: $Request, res: $Response) => res.send('Hello World!'));
app.listen(3000, () => console.log('Example app listening on port 3000!'));

With this change, we only have one warning left:

Looking at the library definition, I am making the call correctly.

flow-typed/npm/express_v4.16.x.js

...
listen(
port: number,
hostname?: string,
callback?: (err?: ?Error) => mixed
): Server;

...

Through hours of troubleshooting this warning, I found an incredibly useful resource that provides an index to the library definitions for Node.js itself.:

In the end, I was not able to get rid of the warning but did end up contributing a bit more information to an existing GitHub issue on the topic.

Wrap Up

The first time I tried to use Flow in a project (was a front-end React + Redux application), I got horribly tangled up in using the third-party library definitions; I ended up giving up.

Recently, in an effort to harden up my back-end code with static typing, I used Flow in a Node.js project and the experience was much better (up until I spent hours troubleshooting that single warning).

Bottom line, I am sufficiently satisfied with Flow (and expect it to get better) to not feel compelled to jump ship to statically typed server languages like the increasingly popular Go.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.

Written by John Tucker

Broad infrastructure, development, and soft-skill background

Responses (1)

Write a response