Flow とは
動的型付けのJavaScriptでも静的型付けができるようになる静的チェッカーです。
つまりJavascript でもTypescriptのように型宣言することができるようになります。
Flow インストール
Flow 有効
ファイルの一番上に
// @flow
を追加する。
Flowのプリミティブ型
型 | 意味 |
---|---|
any |
静的チェック無効。何も書かないとこれ |
mixed |
何の型でも受け取るが、利用時に型ごとに絞込が必要 |
* (実存型) |
代入のたびに強制的な型推論を行う |
number |
数値 |
boolean |
ブール |
string |
文字列 |
'A' | 'B' | 'C' |
AかBかCのどれか |
Object |
オブジェクト |
{ id: number } |
id を持つオブジェクト |
Array<string> |
文字列の配列 |
Set<string> |
文字列のSet |
string[ ] |
文字列の配列 |
Function |
関数 |
Class<User> |
Userクラス |
React.DOM |
React Element |
SyntheticInputEvent<EventTarget> |
React.DOMのEvent |
その他、膨大な数の型が載ってます。
https://www.saltycrane.com/flow-type-cheat-sheet/latest/
Flow の特殊な型
mixed
全ての型を代入できるが、利用するときはチェックが必要。
let val: mixed;
val = {};
val = 1;
val = 'test';
if (typeof val === 'function') {
val();
}
val(); // error
* (実存型)
全ての型を代入できる。また、代入時に強制的に型推論される。
let val: *;
val = 1; // val is number
val = 'test'; // val is string
val = {}; // val is Object
val(); // Error occurs because val is Object
val = 1; // val is number
val.doSomething() // Error occurs because val is number
Maybe ( ? ) の使い方
null も undefined も許可しない
let val: number;
val = 0;
val = undefined; // error
val = null; // error
null と undefined を許可する
let val: ?number;
val = 0;
val = undefined;
val = null;
プロパティの必須有無
必須プロパティあり
let val: { id: number };
val = { id: 1 };
val = { }; // error
必須プロパティなし
let val: { id?: number};
val = {id : 1};
val = { };
おまけ
必須プロパティなし。もしあった場合はnumberかnullかundefinedであること。
let val: { id?: ?number };
val = { id: 1 };
val = { };
val = { id: null };
val = { id: undefined };
val = { id: 'string' }; // error
React + react-redux Component
e.g.
import React from 'react';
import { connect } from 'react-redux';
import type { MapStateToProps } from 'react-redux';
import { Map } from 'immutable';
import type { Map as MapType } from 'immutable';
import { fetchUsers } from 'actions/users';
type Props = {
users: MapType,
selected: string,
};
type State = {
selected: string,
};
export default class UserSelector extends React.Component<Props, State> {
static defaultProps = {
users: new Map()
};
constructor(props: Props) {
super(props);
this.state = { selected: props.selected };
}
componentWillMount() {
this.props.fetchUsers();
}
componentWillReceiveProps(nextProps: Props) {
if (nextProps.selected) {
this.setState({ selected: nextProps.selected });
}
}
render() {
this.props.users.valueSeq().map(user => (
<div>
{user.get('id') === this.state.selected && <p>{user.get('name')} selected</p>}
{user.get('id') !== this.state.selected && <p>{user.get('name')}</p>}
</div>
));
}
};
const mapStateToProps: MapStateToProps<*, *, *> = (state: *) => {
return {
users: state.users,
selected: state.selected,
};
};
const mapDispatchToProps = (dispatch: Dispatch<*>) => ({
fetchUsers : () => dispatch(fetchUsers())
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(UserSelector);
外部ライブラリの型
e.g. flow-typed でライブラリを検索してインストールする。
(´ω`) < npm run flow-typed search moment
> my-project@1.0.0 flow-typed /src
> flow-typed "search" "moment"
• rebasing flow-typed cache...done.
Found definitions:
╔════════╤═════════════════╤══════════════╗
║ Name │ Package Version │ Flow Version ║
╟────────┼─────────────────┼──────────────╢
║ moment │ v2.3.x │ >=v0.34.x ║
╟────────┼─────────────────┼──────────────╢
║ moment │ v2.x.x │ >=v0.28.x ║
╚════════╧═════════════════╧══════════════╝
(´ω`) < npm run flow-typed install moment@v2.3.x --skip
e.g. package.json から依存ライブラリの型情報をまとめてインストールする。
(´ω`) < npm run flow-typed install --skip