mizchi君の記事を見て、だいぶ感想が違ったので書くことにした。
なお、僕はTypeScript信者であることを踏まえてこの記事を読んでほしい。
あと、最初はまじめに記事にしようと思ったけどダルくなってきたのでメモをそのまま投げる。
TypeScriptより良い型推論
Flowパイセンの一番偉いところはTypeScriptより型推論が強いところだと思った。#
/* @flow */
function foo(x) {
return x * 10;
}
foo('Hello, world!');
$> flow
hello.js:5:5,19: string
This type is incompatible with
hello.js:3:10,15: number
関数foo内部のxは、* 演算子を利用しているのでnumberであると推論している。
これが実際の利用箇所でstringを引数にしているので怒ってくれるわけだ。偉いな!
Flow is a static type checker
と謳っているとおり、完全にpure JavaScriptで書かれているプロジェクトに対して、新しいlintの一種であるかのように導入できるのは大きなアドバンテージだろう。
なお、もちろん型注釈を明示的に与えることもできる模様。
/* @flow */
function foo(x) {
return x.reduce((p, c) => p + c.charAt(0), 0);
}
foo([false, true]);
$ flow check
/private/tmp/flow/hello.js:3:33,43: call of method charAt
Property not found in
/private/var/folders/c8/yszwff5d4z57z0d4sn04yy140000gn/T/flow_vvakame/flowlib_7e8f1b7/lib/core.js:54:1,56:1: Boolean
Found 1 error
スゲェ。でもエラーメッセージわかりにくい。
nullを許容しない
ここより抜粋。
/* @flow */
function length(x) {
return x.length;
}
var total = length('Hello') + length(null);
03_Null/nulls.js:4:10,17: property length
Property cannot be accessed on possibly null value
03_Null/nulls.js:7:38,41: null
nullを想定していない関数に対して、nullを渡すと怒られる。
強い。
以下のようなnullチェックがある関数だと怒られないらしい。
強い。
/* @flow */
function length(x) {
if (x !== null) {
return x.length;
} else {
return 0;
}
}
var total = length('Hello') + length(null);
TypeScript 1.4で導入予定のtype guardsに近い発想だ。
しかし、大きなbreaking changeになるのでTypeScriptには少なくともしばらくは入らんだろうなぁ。羨ましい。
型定義
普通にTypeScriptのlib.d.tsを参考にしてるっぽい
コンパイルエラーで表示されたメッセージから以下を拾うことができた。
This type is incompatible with
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the "flow" directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
/* JS primitives
cf. http://typescript.codeplex.com/sourcecontrol/latest#typings/lib.d.ts
*/
配列
Array<number>
形式しか受け付けないのかなと思って以下を試したけど普通にチェック通った。
/* @flow */
function foo(x: number[]) {
return x.reduce((p, c) => c + p, 0);
}
union types
ふつーにある
弱くチェックするモード
/* @flow weak */
型定義ファイルの使い方
コマンドラインオプションで頑張る
多分 .flowconfig に書いてもイケる。
コンパイルの仕方
react-toolsで型注釈機械的に取り除くだけ?
default valueにも対応してるようだけどうまく動かなくね?ブラウザ側が対応すれば使えるみたいなTypeScript以上のストロングスタイルなのかまさか。
そもそも型定義ファイルいるの?
Flowの処理系使ったら既存JSから雑な型定義ファイル生成できそうじゃね?
オナシャス!
TypeScriptとの互換性
今んとこ割りとありそうに見える。
mixedの導入 とか、微妙にTypeScriptにないものがあるような気もする。
Flow is superset of TypeScript 感。
tupleがサポートされている
TypeScriptと同じ感じっぽいけどTypeScriptより頭悪い
/* @flow */
var tup = ["1", 1, 2, "positive"];
tup.unshift(1);
console.log(tup[1] * tup[2]); // unshiftしたので 1st * 2nd は number * string だ!
これがエラーチェックをすり抜ける。
TypeScriptの場合、明示的にtupleと型注釈を与えない限りtupleにならないので、(string | number)[] となる。
nullable の導入
ここより
/* @flow */
var o: ?string = null;
print(o.length);
良さそう…?な気もする?
intersection types
うーん、これunion typesで表現可能な範囲だし、言語設計者が単に入れたかったら入れた感あるな…。
dynamic type tests
ここ
TypeScriptがtype guardsと呼んでいるものをdynamic type testsと呼んでいるっぽい気がする。
生JSに型注釈版のサジェストをくれる
/* @flow */
function foo(x) {
return x.reduce((p, c) => p + c.charAt(0), "");
}
foo(["JavaScript", "TypeScript"]);
$ flow suggest hello.js
/private/tmp/flow/hello.js
--- old
+++ new
@@ -1,6 +1,6 @@
/* @flow */
-function foo(x) {
- return x.reduce((p, c) => p + c.charAt(0), "");
+function foo(x: Array<string>) : string{
+ return x.reduce((p: string, c: string) => : stringp + c.charAt(0), "");
}
foo(["JavaScript", "TypeScript"]);
…強い!!
神機能じゃね?arrow function expressionあたりがちょっとバグってるけど。
第二のインストール方法
$ brew install opam
$ opam init
$ eval `opam config env`
$ opam install flowtype
$ which flow
/Users/vvakame/.opam/system/bin/flow
総評
アンダース・ヘルスバーグ御大の設計は繊細で強いなと思った。
御大だったら入れてないだろコレ…みたいな感想をなんかテキトーに2〜3回くらい思った気がする。