Copyright © DeNA Co.,Ltd. All Rights Reserved.
flow による型のある世界入
門
株式会社 DeNA Games Osaka
技術部 人西 聖樹
masaki.hitonishi@dena.com
Copyright © DeNA Co.,Ltd. All Rights Reserved.
自己紹介
 人西 聖樹(ひとにし まさき)
 Twitter: @sairoutine
 株式会社 DeNA Games Osaka
 Webアプリケーションエンジニア
Copyright © DeNA Co.,Ltd. All Rights Reserved.
今日話すこと
 型とは
 なぜ静的型付けが必要か
 flow とは
 flow と TypeScript の比較
Copyright © DeNA Co.,Ltd. All Rights Reserved.
型
Copyright © DeNA Co.,Ltd. All Rights Reserved.
「型システムとは、プログラムの各部
分を、それが計算する値の種類に沿っ
て分類することにより、プログラムが
ある種の振る舞いを起こさないことを
保証する、計算量的に扱いやすい構文
的手法である。」
Pierce, B. C. (2013) 『型システム入門 −プログラミング言語と型の
理論−』住井英二郎 (監訳), 遠藤他(訳), オーム社.
Copyright © DeNA Co.,Ltd. All Rights Reserved.
例えば Java (型のある言語)とかだと
int a = 1; // ←ここでの int が型
static int square(int param) // ←返り値に int 型を宣言、引数に int 型の
param を宣言
{
int value; // ←ローカル変数に int 型の value を宣言。
value = param * param;
return value;
}
Copyright © DeNA Co.,Ltd. All Rights Reserved.
静的型付けと動的型付け
 静的型付け
⁃ コンパイル時に型をチェックする
⁃ 型がおかしいとそもそも実行すらできない
⁃ Java、C、C# などの言語
 動的型付け
⁃ プログラム実行時にチェックする
⁃ 型がおかしくてもプログラムが実行されるまでわからな
い
⁃ JavaScript、Python、Ruby、Perl などの言語
Copyright © DeNA Co.,Ltd. All Rights Reserved.
JavaScript で使われるデータ型一覧
 数値
 文字列
 論理値
 null
 undefined
 オブジェクト
Copyright © DeNA Co.,Ltd. All Rights Reserved.
JavaScript は動的型付け
 動的型付けなので変数にはどんな型を入れてもよ
い
 関数の引数や返り値も柔軟に修正/変更できる
 簡単!
 静的型付けの言語では、変数にいれるデータの型
は決まっている
 関数の引数や返り値の型を変更すると、関数の呼
び出し側も修正しなければならない
 大変……
Copyright © DeNA Co.,Ltd. All Rights Reserved.
JavaScript は動的型付けのメリットを
選択したプログラミング言語
Copyright © DeNA Co.,Ltd. All Rights Reserved.
しかし、今日では JavaScript に
静的型付けの必要性が叫ばれています。
今回お話する flow も JavaScript に
静的型付けを導入するツールです
Copyright © DeNA Co.,Ltd. All Rights Reserved.
なぜか
Copyright © DeNA Co.,Ltd. All Rights Reserved.
大規模なフロントエンド開発、
開発したフロントエンドシステムの
長期的保守が必要になってきた。
Copyright © DeNA Co.,Ltd. All Rights Reserved.
 長期的に保守されるシステム
 大規模で複雑なシステム
 継続的にリファクタしていくシステム
 ミッションクリティカルなシステム
 保守するエンジニアが入れ替わっていくシステム
→動的型付け言語のメリットが活かせない
Copyright © DeNA Co.,Ltd. All Rights Reserved.
フロントエンドにも静的型付けが
必要。ただし現状フロントエンドを
実装できる言語は JavaScript の一択
Copyright © DeNA Co.,Ltd. All Rights Reserved.
JavaScript に静的型付けを導入したい
Copyright © DeNA Co.,Ltd. All Rights Reserved.
flow
Copyright © DeNA Co.,Ltd. All Rights Reserved.
Flow
 JavaScript のコードに型定義(annotation)を追加
できるようになる
 By Facebook
 型のチェックのみしてくれる
 コンパイラというより型チェッカー
 本番コードでは、Babel 等の仕組みで型定義を
コードから削除する
 日本では flowtype という呼称が一般的ですが、本
スライド内では flow で呼称を統一します。
Copyright © DeNA Co.,Ltd. All Rights Reserved.
Google Trend
「flowtype」で検索(2017/03/14 現在)
Copyright © DeNA Co.,Ltd. All Rights Reserved.
静的型付けのメリット
 コードがより読みやすくなる
⁃ 型定義を読むことで関数を使う際にどんな引数が必要で、ど
んな値が返ってくるか想像をつけることができる
⁃ 引数や返り値の型が決まっているので、予想外の値が引数や
返り値に含まれることを想像しなくてよい
 コードのバグを事前に発見しやすくなる
⁃ 型定義の誤りはコンパイル時にわかる
⁃ 運用して初めて型の誤りによるバグに気づくということが減
る
 IDEのサポートを受けやすくなる
⁃ エディタの補完などが便利に
 リファクタしやすくなる
⁃ リファクタによって、関数の引数や返り値のデータ構造を破
壊してしまっても、コンパイル時に気づくことができる
Copyright © DeNA Co.,Ltd. All Rights Reserved.
静的型付けが有利なシステムとは
 長期間保守されることが想定されるシステム
⁃ コードが後から読みやすいメリット
⁃ コードは書かれる時間より読まれる時間の方が圧倒的に多い
 大規模なシステム
⁃ 複数人で開発する場合
⁃ クラスや関数のインターフェイスを型定義により明確にできる
 継続的にリファクタされるシステム
⁃ リファクタによるデータ定義の破壊に気づくことができる
 ミッションクリティカルなシステム
⁃ 型定義の違いによるバグはコンパイル時に発見できる
⁃ 型というルールを設けることでバグを減らせる
 システムに関わる人が入れ替わるシステム
⁃ 人が入れ替わっても型定義はコードに残る
⁃ 関数の引数や戻り値を、コードを読み解いて調べなくても良い
Copyright © DeNA Co.,Ltd. All Rights Reserved.
実際のコード例
Copyright © DeNA Co.,Ltd. All Rights Reserved.
flow を使う準備
# babel の準備
npm install -g browserify
npm install --save-dev babelify@7.2.0 babel-preset-es2015
# flow の準備
npm install --save-dev flow-bin babel-plugin-transform-flow-
strip-types
echo '{"presets": ["es2015"],"plugins": ["babel-plugin-
transform-flow-strip-types"]}' > .babelrc
flow-bin がチェッカー本体で、
babel-plugin-transform-flow-strip-typesが、
Babel によるトランスパイル時にコード上の型定義を
除去してくれるプラグイン
Copyright © DeNA Co.,Ltd. All Rights Reserved.
flow を使う準備
"scripts": {
"flow": "$(npm bin)/flow",
},
package.json に flow チェッカーを追加
[ignore]
.*/node_modules/.*
[include]
[libs]
[options]
.flowconfig を作成して node_modules 配下を無視する設定を追加
Copyright © DeNA Co.,Ltd. All Rights Reserved.
サンプルコード
// @flow
(function() {
function foo(x) {
return x * 10;
}
foo('Hello, world!');
});
文字列「Hello, World!」に
掛け算をおこなっている、いかにも怪しいコード
// @flow を追加することで、flow のチェック対象となる
Copyright © DeNA Co.,Ltd. All Rights Reserved.
$ npm run flow
5: return x * 10;
^ string. The operand of an arithmetic
operation must be a number.
特にまだ型定義は追加していないが、
flow がエラーを吐いてくれる。
→引数に String を渡しているにも関わらず、
関数内で数値として扱っているのを
Flow が発見してエラーにしている。
→ flow の 型推論 機能
Copyright © DeNA Co.,Ltd. All Rights Reserved.
サンプルコード
// @flow
(function() {
function foo(x: string, y: number): number {
return x.length * y;
}
foo('Hello', 42);
});
関数の引数に型定義を追加するパターン
Copyright © DeNA Co.,Ltd. All Rights Reserved.
サンプルコード
// @flow
function total(numbers: Array<number>) {
var result = 0;
for (var i = 0; i < numbers.length; i++) {
result += numbers[i];
}
return result;
}
total([1, 2, 3, 4]);
配列の型定義
Copyright © DeNA Co.,Ltd. All Rights Reserved.
サンプルコード
// @flow
// 独自の型
type Comment = {
author: string;
text: string;
};
const comment: Comment = {
author: "sai",
text: "hello, world!",
};
function create_text (comment : Comment) : string {
return comment.author + " says " + comment.text;
}
console.log(create_text(comment));
独自の型定義も可能
Copyright © DeNA Co.,Ltd. All Rights Reserved.
サンプルコード
// @flow
(function() {
function length(x) {
return x.length;
}
var total = length('Hello') + length(null);
})
Null が入る場合
Copyright © DeNA Co.,Ltd. All Rights Reserved.
$ npm run flow
7: return x.length;
^ property `length`. Property cannot be accessed on
possibly null value
7: return x.length;
^ null
Null が入る可能性があるため、エラーになる。
flow は Null 安全
Copyright © DeNA Co.,Ltd. All Rights Reserved.
// @flow
(function() {
function length(x) {
if (x !== null) {
return x.length;
} else {
return 0;
}
}
var total = length('Hello') + length(null);
});
Null であることをきちんとチェックすればOK
Copyright © DeNA Co.,Ltd. All Rights Reserved.
(function() {
function length(x : ?string) : number {
if (x != null) {
return x.length;
} else {
return 0;
}
}
var total = length('Hello') + length(null);
});
型推論に任せず、Null を許容する型を
定義する方法も flow にはある
Copyright © DeNA Co.,Ltd. All Rights Reserved.
React や Flux, Redux との連携
 容易にできるらしい
 React 周りに詳しくないので詳細は別の方の資料にお任せ
します。
 【Electron + react + flowtype】TweetDeckライクな
pixivクライアントPixivDeckをつくった
 http://qiita.com/akameco/items/fa80b9a325e3d1e8fd
5b
 Type-Safe Flux Using Flowtype
 https://speakerdeck.com/joere/type-safe-flux-using-
flowtype
Copyright © DeNA Co.,Ltd. All Rights Reserved.
JavaScript に静的型付けを導入するには、
TypeScript を使う選択肢もある
Copyright © DeNA Co.,Ltd. All Rights Reserved.
TypeScript
 AltJS
 By Microsoft
 ES6 ベース
 型定義を追加することができる
 コンパイラが型定義をチェックしてくれる
 JavaScript というより TypeScript という言語
 WebStorm や Visual Studio Code などの IDE によるサ
ポートがある
 Null 安全でない(TypeScript 2.0 から strictNullChecks オ
プションで Null 安全に)
 静的型付けの恩恵を受けたい場合、TypeScript を採用する
手もある
Copyright © DeNA Co.,Ltd. All Rights Reserved.
flow と TypeScript の比較
 flow
⁃ 既存の JavaScript コードにも適用できる
⁃ 一部のコードにだけ静的型付けを適用することもできる
⁃ JavaScript + 型定義なので、学習コスト低
⁃ あくまで型チェッカー。それ以上のことはしない
 TypeScript
⁃ 型定義以外の恩恵(クラス定義構文など)が受けられる
⁃ 導入するとなると、全コードを TypeScript に置き換える覚悟
⁃ TypeScript の文法などの学習が必要
⁃ IDEのサポートが豊富(Visual Studio Code や WebStorm など)
Copyright © DeNA Co.,Ltd. All Rights Reserved.
まとめ
 フロントエンド開発の大規模化、長期的な保守に伴い、静
的型付けの重要性が認識されてきた
 JavaScript に静的型付けを導入するには、flow と
TypeScript のおおまかに二種類が存在する。
 flow は既存のシステムに追加する場合に、TypeScript は
新規のシステムに追加する場合に便利
 両者とも型定義は非常に似通っている。
 Null 安全についての扱いが両者は異なる
 プロジェクトやチームにとって最適な選択で、静的型付け
を導入しよう
Copyright © DeNA Co.,Ltd. All Rights Reserved.
ご清聴ありがとうございました

flow による型のある世界入門

  • 1.
    Copyright © DeNACo.,Ltd. All Rights Reserved. flow による型のある世界入 門 株式会社 DeNA Games Osaka 技術部 人西 聖樹 masaki.hitonishi@dena.com
  • 2.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 自己紹介  人西 聖樹(ひとにし まさき)  Twitter: @sairoutine  株式会社 DeNA Games Osaka  Webアプリケーションエンジニア
  • 3.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 今日話すこと  型とは  なぜ静的型付けが必要か  flow とは  flow と TypeScript の比較
  • 4.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 型
  • 5.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 「型システムとは、プログラムの各部 分を、それが計算する値の種類に沿っ て分類することにより、プログラムが ある種の振る舞いを起こさないことを 保証する、計算量的に扱いやすい構文 的手法である。」 Pierce, B. C. (2013) 『型システム入門 −プログラミング言語と型の 理論−』住井英二郎 (監訳), 遠藤他(訳), オーム社.
  • 6.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 例えば Java (型のある言語)とかだと int a = 1; // ←ここでの int が型 static int square(int param) // ←返り値に int 型を宣言、引数に int 型の param を宣言 { int value; // ←ローカル変数に int 型の value を宣言。 value = param * param; return value; }
  • 7.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 静的型付けと動的型付け  静的型付け ⁃ コンパイル時に型をチェックする ⁃ 型がおかしいとそもそも実行すらできない ⁃ Java、C、C# などの言語  動的型付け ⁃ プログラム実行時にチェックする ⁃ 型がおかしくてもプログラムが実行されるまでわからな い ⁃ JavaScript、Python、Ruby、Perl などの言語
  • 8.
    Copyright © DeNACo.,Ltd. All Rights Reserved. JavaScript で使われるデータ型一覧  数値  文字列  論理値  null  undefined  オブジェクト
  • 9.
    Copyright © DeNACo.,Ltd. All Rights Reserved. JavaScript は動的型付け  動的型付けなので変数にはどんな型を入れてもよ い  関数の引数や返り値も柔軟に修正/変更できる  簡単!  静的型付けの言語では、変数にいれるデータの型 は決まっている  関数の引数や返り値の型を変更すると、関数の呼 び出し側も修正しなければならない  大変……
  • 10.
    Copyright © DeNACo.,Ltd. All Rights Reserved. JavaScript は動的型付けのメリットを 選択したプログラミング言語
  • 11.
    Copyright © DeNACo.,Ltd. All Rights Reserved. しかし、今日では JavaScript に 静的型付けの必要性が叫ばれています。 今回お話する flow も JavaScript に 静的型付けを導入するツールです
  • 12.
    Copyright © DeNACo.,Ltd. All Rights Reserved. なぜか
  • 13.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 大規模なフロントエンド開発、 開発したフロントエンドシステムの 長期的保守が必要になってきた。
  • 14.
    Copyright © DeNACo.,Ltd. All Rights Reserved.  長期的に保守されるシステム  大規模で複雑なシステム  継続的にリファクタしていくシステム  ミッションクリティカルなシステム  保守するエンジニアが入れ替わっていくシステム →動的型付け言語のメリットが活かせない
  • 15.
    Copyright © DeNACo.,Ltd. All Rights Reserved. フロントエンドにも静的型付けが 必要。ただし現状フロントエンドを 実装できる言語は JavaScript の一択
  • 16.
    Copyright © DeNACo.,Ltd. All Rights Reserved. JavaScript に静的型付けを導入したい
  • 17.
    Copyright © DeNACo.,Ltd. All Rights Reserved. flow
  • 18.
    Copyright © DeNACo.,Ltd. All Rights Reserved. Flow  JavaScript のコードに型定義(annotation)を追加 できるようになる  By Facebook  型のチェックのみしてくれる  コンパイラというより型チェッカー  本番コードでは、Babel 等の仕組みで型定義を コードから削除する  日本では flowtype という呼称が一般的ですが、本 スライド内では flow で呼称を統一します。
  • 19.
    Copyright © DeNACo.,Ltd. All Rights Reserved. Google Trend 「flowtype」で検索(2017/03/14 現在)
  • 20.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 静的型付けのメリット  コードがより読みやすくなる ⁃ 型定義を読むことで関数を使う際にどんな引数が必要で、ど んな値が返ってくるか想像をつけることができる ⁃ 引数や返り値の型が決まっているので、予想外の値が引数や 返り値に含まれることを想像しなくてよい  コードのバグを事前に発見しやすくなる ⁃ 型定義の誤りはコンパイル時にわかる ⁃ 運用して初めて型の誤りによるバグに気づくということが減 る  IDEのサポートを受けやすくなる ⁃ エディタの補完などが便利に  リファクタしやすくなる ⁃ リファクタによって、関数の引数や返り値のデータ構造を破 壊してしまっても、コンパイル時に気づくことができる
  • 21.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 静的型付けが有利なシステムとは  長期間保守されることが想定されるシステム ⁃ コードが後から読みやすいメリット ⁃ コードは書かれる時間より読まれる時間の方が圧倒的に多い  大規模なシステム ⁃ 複数人で開発する場合 ⁃ クラスや関数のインターフェイスを型定義により明確にできる  継続的にリファクタされるシステム ⁃ リファクタによるデータ定義の破壊に気づくことができる  ミッションクリティカルなシステム ⁃ 型定義の違いによるバグはコンパイル時に発見できる ⁃ 型というルールを設けることでバグを減らせる  システムに関わる人が入れ替わるシステム ⁃ 人が入れ替わっても型定義はコードに残る ⁃ 関数の引数や戻り値を、コードを読み解いて調べなくても良い
  • 22.
    Copyright © DeNACo.,Ltd. All Rights Reserved. 実際のコード例
  • 23.
    Copyright © DeNACo.,Ltd. All Rights Reserved. flow を使う準備 # babel の準備 npm install -g browserify npm install --save-dev babelify@7.2.0 babel-preset-es2015 # flow の準備 npm install --save-dev flow-bin babel-plugin-transform-flow- strip-types echo '{"presets": ["es2015"],"plugins": ["babel-plugin- transform-flow-strip-types"]}' > .babelrc flow-bin がチェッカー本体で、 babel-plugin-transform-flow-strip-typesが、 Babel によるトランスパイル時にコード上の型定義を 除去してくれるプラグイン
  • 24.
    Copyright © DeNACo.,Ltd. All Rights Reserved. flow を使う準備 "scripts": { "flow": "$(npm bin)/flow", }, package.json に flow チェッカーを追加 [ignore] .*/node_modules/.* [include] [libs] [options] .flowconfig を作成して node_modules 配下を無視する設定を追加
  • 25.
    Copyright © DeNACo.,Ltd. All Rights Reserved. サンプルコード // @flow (function() { function foo(x) { return x * 10; } foo('Hello, world!'); }); 文字列「Hello, World!」に 掛け算をおこなっている、いかにも怪しいコード // @flow を追加することで、flow のチェック対象となる
  • 26.
    Copyright © DeNACo.,Ltd. All Rights Reserved. $ npm run flow 5: return x * 10; ^ string. The operand of an arithmetic operation must be a number. 特にまだ型定義は追加していないが、 flow がエラーを吐いてくれる。 →引数に String を渡しているにも関わらず、 関数内で数値として扱っているのを Flow が発見してエラーにしている。 → flow の 型推論 機能
  • 27.
    Copyright © DeNACo.,Ltd. All Rights Reserved. サンプルコード // @flow (function() { function foo(x: string, y: number): number { return x.length * y; } foo('Hello', 42); }); 関数の引数に型定義を追加するパターン
  • 28.
    Copyright © DeNACo.,Ltd. All Rights Reserved. サンプルコード // @flow function total(numbers: Array<number>) { var result = 0; for (var i = 0; i < numbers.length; i++) { result += numbers[i]; } return result; } total([1, 2, 3, 4]); 配列の型定義
  • 29.
    Copyright © DeNACo.,Ltd. All Rights Reserved. サンプルコード // @flow // 独自の型 type Comment = { author: string; text: string; }; const comment: Comment = { author: "sai", text: "hello, world!", }; function create_text (comment : Comment) : string { return comment.author + " says " + comment.text; } console.log(create_text(comment)); 独自の型定義も可能
  • 30.
    Copyright © DeNACo.,Ltd. All Rights Reserved. サンプルコード // @flow (function() { function length(x) { return x.length; } var total = length('Hello') + length(null); }) Null が入る場合
  • 31.
    Copyright © DeNACo.,Ltd. All Rights Reserved. $ npm run flow 7: return x.length; ^ property `length`. Property cannot be accessed on possibly null value 7: return x.length; ^ null Null が入る可能性があるため、エラーになる。 flow は Null 安全
  • 32.
    Copyright © DeNACo.,Ltd. All Rights Reserved. // @flow (function() { function length(x) { if (x !== null) { return x.length; } else { return 0; } } var total = length('Hello') + length(null); }); Null であることをきちんとチェックすればOK
  • 33.
    Copyright © DeNACo.,Ltd. All Rights Reserved. (function() { function length(x : ?string) : number { if (x != null) { return x.length; } else { return 0; } } var total = length('Hello') + length(null); }); 型推論に任せず、Null を許容する型を 定義する方法も flow にはある
  • 34.
    Copyright © DeNACo.,Ltd. All Rights Reserved. React や Flux, Redux との連携  容易にできるらしい  React 周りに詳しくないので詳細は別の方の資料にお任せ します。  【Electron + react + flowtype】TweetDeckライクな pixivクライアントPixivDeckをつくった  http://qiita.com/akameco/items/fa80b9a325e3d1e8fd 5b  Type-Safe Flux Using Flowtype  https://speakerdeck.com/joere/type-safe-flux-using- flowtype
  • 35.
    Copyright © DeNACo.,Ltd. All Rights Reserved. JavaScript に静的型付けを導入するには、 TypeScript を使う選択肢もある
  • 36.
    Copyright © DeNACo.,Ltd. All Rights Reserved. TypeScript  AltJS  By Microsoft  ES6 ベース  型定義を追加することができる  コンパイラが型定義をチェックしてくれる  JavaScript というより TypeScript という言語  WebStorm や Visual Studio Code などの IDE によるサ ポートがある  Null 安全でない(TypeScript 2.0 から strictNullChecks オ プションで Null 安全に)  静的型付けの恩恵を受けたい場合、TypeScript を採用する 手もある
  • 37.
    Copyright © DeNACo.,Ltd. All Rights Reserved. flow と TypeScript の比較  flow ⁃ 既存の JavaScript コードにも適用できる ⁃ 一部のコードにだけ静的型付けを適用することもできる ⁃ JavaScript + 型定義なので、学習コスト低 ⁃ あくまで型チェッカー。それ以上のことはしない  TypeScript ⁃ 型定義以外の恩恵(クラス定義構文など)が受けられる ⁃ 導入するとなると、全コードを TypeScript に置き換える覚悟 ⁃ TypeScript の文法などの学習が必要 ⁃ IDEのサポートが豊富(Visual Studio Code や WebStorm など)
  • 38.
    Copyright © DeNACo.,Ltd. All Rights Reserved. まとめ  フロントエンド開発の大規模化、長期的な保守に伴い、静 的型付けの重要性が認識されてきた  JavaScript に静的型付けを導入するには、flow と TypeScript のおおまかに二種類が存在する。  flow は既存のシステムに追加する場合に、TypeScript は 新規のシステムに追加する場合に便利  両者とも型定義は非常に似通っている。  Null 安全についての扱いが両者は異なる  プロジェクトやチームにとって最適な選択で、静的型付け を導入しよう
  • 39.
    Copyright © DeNACo.,Ltd. All Rights Reserved. ご清聴ありがとうございました