Help us understand the problem. What is going on with this article?

FlowのドキュメントにあるコードをひたすらTypeScriptのPlaygroundで試す

More than 1 year has passed since last update.

Flow 0.74
Typescript 2.9

TypeScriptの設定は以下な感じ

image.png

先にまとめ

やってみることによって学びがあった。良かった。

  • FlowのObjectTypeは必要なプロパティがあれば同じ型として使えるがTypeScriptの場合はそうではない。
  • 基本型はだいたい同じだが、mixedがないのとvoidの挙動が違う。
  • Maybe型がない。
  • TypeScriptは型を書かないとanyになるがFlowは推論は推論してくれる

多分、お互いに似たようなことはできるが、実際にやるにはそれなりの経験が必要そうだ。逆をやってみるのも面白そう。
これをやってみた感じからするとFlowのほうが好み。

Stringへの暗黙型変換

https://flow.org/en/docs/types/primitives/#toc-strings

// @flow
"foo" + "foo"; // Works!
"foo" + 42;    // Works!
"foo" + {};    // Error!
"foo" + [];    // Error!

TypeScriptはエラーにならなかった。+演算子を使うときは気をつけて。

Maybe

https://flow.org/en/docs/types/primitives/#toc-maybe-types

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

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

残念ながら未対応。自前で実装するしかなさそう。

Mixed

https://flow.org/en/docs/types/mixed/

// @flow
function stringify(value: mixed) {
  // ...
}

stringify("foo");
stringify(3.14);
stringify(null);
stringify({});

そもそもmixedが存在しない模様。
Union型で代用できそうな気はする。

Variables

Reassigning variables

https://flow.org/en/docs/types/variables/#toc-reassigning-variables

let foo = 42;

if (Math.random()) foo = true;
if (Math.random()) foo = "hello";

let isOneOf: number | boolean | string = foo; // Works!

TypeScriptでは代入した時点で foo が numberと決まってしまう。true や "hello"は代入しようとすると型エラーに。flowは型の再設定が可能で、Union Typeになる。

以下の様に書いてあげるとエラーは消える

let foo: number | boolean | string = 42;

if (Math.random()) foo = true;
if (Math.random()) foo = "hello";

let isOneOf: number | boolean | string = foo; // Works!

Function this

https://flow.org/en/docs/types/functions/#toc-function-this

function method() {
  return this;
}

var num: number = method.call(42);
// $ExpectError
var str: string = method.call(42);

TypeScriptでは暗黙のanyでエラーになる。
TypeScriptなら以下でどうだろうか。

function method<T>(this: T): T {
  return this;
}

var num: number = <number>method.call(42);
// $ExpectError
var str: string = <number>method.call(42);

Predicate Functions

https://flow.org/en/docs/types/functions/#toc-predicate-functions

function truthy(a, b): boolean %checks {
  return !!a && !!b;
}

そもそも %checksなぞTypeScriptにない。
TypeScriptでの解決方法は浮かばず。

Unsealed Object

// @flow
var obj = {};

obj.foo = 1;       // Works!
obj.bar = true;    // Works!
obj.baz = 'three'; // Works!

これも同じようにする方法がわからず。すべてのkeyとその型を書く以外の方法がわからなかった。

Exact Object

https://flow.org/en/docs/types/objects/#toc-exact-object-types

// @flow
var foo: {| foo: string |} = { foo: "Hello", bar: "World!" }; // Error!

TypeScriptには無い文法だが、interfaceを使うか

// @flow
interface Hoge { foo: string }
var foo: Hoge = { foo: "Hello", bar: "World!" }; // Error!

Objects as maps

https://flow.org/en/docs/types/objects/#toc-objects-as-maps

// @flow
var o: { [string]: number } = {};
o["foo"] = 0;
o["bar"] = 1;
var foo: number = o["foo"];

TypeScriptは文法が違う。labelをつけてあげればよい。labelをつけてもFlowでは動作する。

// @flow
var o: { [key: string]: number } = {};
o["foo"] = 0;
o["bar"] = 1;
var foo: number = o["foo"];

Tuple type

https://flow.org/en/docs/types/tuples/

// @flow
let tuple: [number, boolean, string] = [1, true, "three"];

let none: void = tuple[3]; // error

TypeScriptでは別の要因でエラーになる。tuple[3]の利用にはエラーがでない。

// @flow
let tuple: [number, boolean, string] = [1, true, "three"];

let none: string | number | boolean = tuple[3]; // error

これだとエラーにならないので、Tupleというより配列として認識している。

strictly enforced tuple length arity

https://flow.org/en/docs/types/tuples/#toc-strictly-enforced-tuple-length-arity

// @flow
let tuple: [number, number] = [1, 2];
// $ExpectError
let array: Array<number>    = tuple; // Error!

TypeScriptではエラーにならない。tupleではなく配列として扱われるため。

// @flow
let tuple: [number, number] = [1, 2];
tuple.join(', '); // Works!
// $ExpectError
tuple.push(3);    // Error!

これも同様。

Opaque Type Aliases

opaque type ID = string;

TypeScriptは対応していない。がんばれば似たようなことはできるはず。

Interface Types

https://flow.org/en/docs/types/interfaces/

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

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

// $ExpectError
const foo: Foo = new Bar(); // Error!

TypeScriptではエラーにならない。
構造的部分型になるため。Flowでは別の型として扱われる。
根本的な思想の違いと考えられる。

Flowでやるなら共通インターフェイスを用意する

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

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

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

// $ExpectError
const foo: Base = new Bar(); // Error!
foo.serialize();

read only and write only

https://flow.org/en/docs/types/interfaces/#toc-interface-property-variance-read-only-and-write-only

interface MyInterface {
  +covariant: number;     // read-only
  -contravariant: number; // write-only
}

TypeScriptではreadonlyの書き方は違うし、writeonlyはやり方しらない。

Generic Type

https://flow.org/en/docs/types/generics/

// @flow

type IdentityWrapper = {
  func<T>(T): T
}

function identity(value) {
  return value;
}

function genericIdentity<T>(value: T): T {
  return value;
}

// $ExpectError
const bad: IdentityWrapper = { func: identity }; // Error!
const good: IdentityWrapper = { func: genericIdentity }; // Works!

TypeScriptだとidentityが暗黙のanyでエラーになってしまう。
下記のコードで代用してみたが、badはエラーにならなかった。

type IdentityWrapper = {
  func<T>(t: T): T
}

function identity(value: any): any {
  return value;
}

function genericIdentity<T>(value: T): T {
  return value;
}

// $ExpectError
const bad: IdentityWrapper = { func: identity }; // Error!
const good: IdentityWrapper = { func: genericIdentity }; // Works!

型の制約

// @flow
function logFoo<T: { foo: string }>(obj: T): T {
  console.log(obj.foo); // Works!
  return obj;
}

logFoo({ foo: 'foo', bar: 'bar' });  // Works!
// $ExpectError
logFoo({ bar: 'bar' }); // Error!

TypeScriptだと制約の付け方が違う。
extendsで指定できる

// @flow
function logFoo<T extends { foo: string } >(obj: T): T {
  console.log(obj.foo); // Works!
  return obj;
}

logFoo({ foo: 'foo', bar: 'bar' });  // Works!
// $ExpectError
logFoo({ bar: 'bar' }); // Error!

リテラル値のあるオブジェクトのUnion Type

// @flow
type Success = { success: true, value: boolean };
type Failed  = { success: false, error: string };

type Response = Success | Failed;

function handleResponse(response: Response) {
  if (response.success) {
    var value: boolean = response.value; // Works!
  } else {
    var error: string = response.error; // Works!
  }
}

この辺はオブジェクト型の問題なのでどうしようもない。

以下のようにしてもだめだった。

// @flow
interface Success {
    success: true,
    value: boolean,
}

interface Failed {
    success: false,
    error: string,
}

type Response_ = Success | Failed;

function handleResponse(response: Response_) {
  if (response.success) {
    var value: boolean = response.value; // Works!
  } else {
    var error: string = response.error; // Works!
  }
}

typeof

typeof type syntax

https://flow.org/en/docs/types/typeof/#toc-typeof-type-syntax

// @flow
let num1 = 42;
let num2: typeof num1 = 3.14;     // Works!
// $ExpectError
let num3: typeof num1 = 'world';  // Error!

let bool1 = true;
let bool2: typeof bool1 = false;  // Works!
// $ExpectError
let bool3: typeof bool1 = 42;     // Error!

let str1 = 'hello';
let str2: typeof str1 = 'world'; // Works!
// $ExpectError
let str3: typeof str1 = false;   // Error!

let bool2: typeof bool1 = false; // Works!がエラーになる。 bool1 の型はtrueと認識してしまう。どうしようもなさそう。

Typeof inherits behaviors of other types

https://flow.org/en/docs/types/typeof/#toc-typeof-inherits-behaviors-of-other-types

// @flow
class MyClass {
  method(val: number) { /* ... */ }
}

class YourClass {
  method(val: number) { /* ... */ }
}

// $ExpectError
let test1: typeof MyClass = YourClass; // Error!
let test2: typeof MyClass = MyClass;   // Works!

これまでの傾向からわかってるが一応。TypeScriptではエラーにならない。

Type Cast

https://flow.org/en/docs/types/casting/#toc-type-cast-expression-syntax

(1: number)

TypeScriptだとエラーになった。文法の違い。

1 as number

と書けばいいはず。

Utility Type

TypeScriptは全滅するはず。省略。

Module Types

PlayGroundでは再現する方法がうかばないので、省略

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした