Use Flow to detect your JS

Keywords: Javascript TypeScript ECMAScript Attribute

Recently, I saw an introduction about Flow in an article. I think it's very good. Although it's easy to use Typescript in a project before, it's a bit cumbersome to use Flow again, but it's always right to learn more.

brief introduction

JS, as a scripting language, has no type checking. This feature is sometimes used very well, but when you are working on a larger project, you will find that this is actually a terrible thing, because programmers who work with you often don't know exactly what type of code you are writing is correct, and it's also troublesome when refactoring code. So based on this requirement, we have the production of Typescript and Flow. Today we mainly introduce Flow.

install

Because the author has been using WebStorm, there is some support for Flow within WebStorm, so if you also use WebStorm, it will be much more convenient.

yarn add --dev flow-bin babel-cli babel-preset-flow

After installing the above package, create the. babelrc file:

{
  "presets": ["flow"]
}

Setting up WebStorm

With File > Settings > Languages & Frameworks > JavaScript as shown below, Flow package can choose flow-bin under your project, and of course you can install flow-bin globally, then you can use Flow in every project after setting up here.

Flow-Settings

flow can't be used directly in node or browser environments, so we have to compile with babel before we can use it:


Snipaste_2018-01-15_23-54-48.png

Now that the environment is ready, there is only one last step to initialize this project as a Flow project:

yarn run flow init
Snipaste_2018-01-16_00-00-14.png

Now when we use Flow in a project, WebStorm can give intelligent hints.

Use

type

The latest ECMAScript standard defines seven data types:

These types are also used as annotations in Flow:

Use the original type:

// @flow
function method(x: number, y: string, z: boolean) {
  // ...
}

method(3.14, "hello", true);

Use object types:

// @flow
function method(x: Number, y: String, z: Boolean) {
  // ...
}

method(new Number(42), new String("world"), new Boolean(false));

It's important to note that the lowercase number is the original type, while the uppercase Number is the constructor of JavaScript and the object type.

Boolean

In Flow, typing is not converted by default. If you need to convert a type, use either explicit or implicit conversion, for example:

// @flow
function acceptsBoolean(value: boolean) {
  // ...
}

acceptsBoolean(true);  // Works!
acceptsBoolean(false); // Works!
acceptsBoolean("foo"); // Error!
acceptsBoolean(Boolean("foo")); // Works!
acceptsBoolean(!!("foo")); // Works!

Number

// @flow
function acceptsNumber(value: number) {
  // ...
}

acceptsNumber(42);       // Works!
acceptsNumber(3.14);     // Works!
acceptsNumber(NaN);      // Works!
acceptsNumber(Infinity); // Works!
acceptsNumber("foo");    // Error!

null and void

JavaScript has both null and undefined. Flow treats these as separate types: null and void (void denotes undefined type)

// @flow
function acceptsNull(value: null) {
  /* ... */
}

function acceptsUndefined(value: void) {
  /* ... */
}

acceptsNull(null);      // Works!
acceptsNull(undefined); // Error!
acceptsUndefined(null);      // Error!
acceptsUndefined(undefined); // Works!

Maybe type

Perhaps types are used for optional values, and you can create them by adding a question mark (such as? string or? number) before the type.

In addition to the question mark, the following type may also be null or void.

// @flow
function acceptsMaybeString(value: ?string) {
  // ...
}

acceptsMaybeString("bar");     // Works!
acceptsMaybeString(undefined); // Works!
acceptsMaybeString(null);      // Works!
acceptsMaybeString();          // Works!

Optional object properties

Object types can have optional attributes, question marks? After attribute names.

{ propertyName?: string }

In addition to their set value types, these optional attributes can also be completely omitted by void. But they can't null.

// @flow
function acceptsObject(value: { foo?: string }) {
  // ...
}

acceptsObject({ foo: "bar" }); // Works!
acceptsObject({ foo: undefined }); // Works!
acceptsObject({ foo: null }); // Error!
acceptsObject({}); // Works!

Optional function parameters

Functions can have optional parameters, where the question mark? Appears after the parameter name. Again, this parameter cannot be null.

// @flow
function acceptsOptionalString(value?: string) {
  // ...
}

acceptsOptionalString("bar");     // Works!
acceptsOptionalString(undefined); // Works!
acceptsOptionalString(null);      // Error!
acceptsOptionalString();          // Works!

Text type

The text type uses a specific value as the type:

function foo(value: 2) {}

foo(2); // Work!
foo(3); // Error!
foo('2'); // Error!

You can use these types of raw values:

  • Boer: true or false
  • Numbers: like 42 or 3.14
  • String: Like "foo" or "bar"
// @flow
function getColor(name: "success" | "warning" | "danger") {
  switch (name) {
    case "success" : return "green";
    case "warning" : return "yellow";
    case "danger"  : return "red";
  }
}

getColor("success"); // Works!
getColor("danger");  // Works!
// $ExpectError
getColor("error");   // Error!

Mixed type mixed

Sometimes we can't determine what type of value we need. At this point we can use mixed type to express it. But before using the value, we need to determine which type it is, otherwise it will cause errors.

// @flow
function stringify(value: mixed) {
  // $ExpectError
  return "" + value; // Error!
}

stringify("foo");
// @flow
function stringify(value: mixed) {
  if (typeof value === 'string') {
    return "" + value; // Works!
  } else {
    return "";
  }
}

stringify("foo");

any type

If you want a way to choose not to use type checkers, any is the way to do this.

The use of any is completely unsafe and should be avoided as far as possible.

For example, the following code does not report any errors:

// @flow
function add(one: any, two: any): number {
  return one + two;
}

add(1, 2);     // Works.
add("1", "2"); // Works.
add({}, []);   // Works.

Interface type interface

You can use interface to declare the structure of the class you expect.

// @flow
interface Serializable {
  serialize(): string;
}

class Foo {
  serialize() { return '[Foo]'; }
}

class Bar {
  serialize() { return '[Bar]'; }
}

const foo: Serializable = new Foo(); // Works!
const bar: Serializable = new Bar(); // Works!

You can also use implements to tell Flow that you want classes to match an interface. This prevents incompatible changes when editing classes.

// @flow
interface Serializable {
  serialize(): string;
}

class Foo implements Serializable {
  serialize() { return '[Foo]'; } // Works!
}

class Bar implements Serializable {
  // $ExpectError
  serialize() { return 42; } // Error!
}

Array type

To create an array type, you can use the Array < Type > type, where Type is the type of element in the array. For example, create a type Array < number > for the number array you use.

let arr: Array<number> = [1, 2, 3];

So much for the time being. There are some types of articles that are not mentioned. For more details, please Flow official website Check in.

Posted by Harry57 on Sat, 18 May 2019 15:58:25 -0700