Oliver Zeigermann / @DJCordhose
http://djcordhose.github.io/flow-vs-typescript/2016_hhjs.html
Most recent version including TypeScript 2.0 can be found here (might be work in progress): http://djcordhose.github.io/flow-vs-typescript/flow-typescript-2.html
type annotations
JSON style data structures
as a close second place: find usages
let obj: string;
obj = 'yo';
// Error: Type 'number' is not assignable to type 'string'.
obj = 10;
// types can be inferred (return type)
function sayIt(what: string) {
return `Saying: ${what}`;
}
const said: string = sayIt(obj);
class Sayer {
// mandatory
what: string;
constructor(what: string) {
this.what = what;
}
// return type if you want to
sayIt(): string {
return `Saying: ${this.what}`;
}
}
let obj: string;
obj = 'yo';
// Error: number: This type is incompatible with string
obj = 10;
function sayIt(what: string) {
return `Saying: ${what}`;
}
const said: string = sayIt(obj);
class Sayer {
what: string;
constructor(what: string) {
this.what = what;
}
sayIt(): string {
return `Saying: ${this.what}`;
}
}
Those basic features help with documentation, refactoring, and IDE support
function foo(num: number) {
if (num > 10) {
return 'cool';
}
}
// cool
const result: string = foo(100);
console.log(result.toString());
// still cool?
console.log(foo(1).toString());
// error at runtime
"Cannot read property 'toString' of undefined"
TypeScript does not catch this
function foo(num: number) {
if (num > 10) {
return 'cool';
}
}
// error: call of method `toString`.
// Method cannot be called on possibly null value
console.log(foo(100).toString());
Flow does catch this
But why?
The inferred type is something else
// error: return undefined. This type is incompatible with string
function foo(num: number): string {
if (num > 10) {
return 'cool';
}
}
// nullable type: the one inferred
function foo(num: number): ?string {
if (num > 10) {
return 'cool';
}
}
// to fix this, we need to check the result
const fooed: ?string = foo(100);
if (fooed) {
fooed.toString();
}
Types are nullable in TypeScript
Types are non-nullable by default in Flow
Nullable types in Flow also possible
Non-nullable types not yet present in TypeScript
(
but there is hope
)
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
// just to make this different from cat
goodBoyFactor: number;
}
class Cat extends Animal {
purrFactor: number;
}
Types can be parameterized by others
Most common with collection types
let cats: Array<Cat> = []; // can only contain cats
let animals: Array<Animal> = []; // can only contain animals
// nope, no cat
cats.push(10);
// nope, no cat
cats.push(new Animal('Fido'));
// cool, is a cat
cats.push(new Cat('Purry'));
// cool, cat is a sub type of animal
animals.push(new Cat('Purry'));
let cats: Array<Cat> = []; // can only contain cats
let animals: Array<Animal> = []; // can only contain animals
// error TS2322: Type 'Animal[]' is not assignable to type 'Cat[]'.
// Type 'Animal' is not assignable to type 'Cat'.
// Property 'purrFactor' is missing in type 'Animal'.
// cats = animals;
// wow, works, but is no longer safe
animals = cats;
// because those are now all cool
animals.push(new Dog('Brutus'));
animals.push(new Animal('Twinky'));
// ouch:
cats.forEach(cat => console.log(`Cat: ${cat.name}`));
// Cat: Purry
// Cat: Brutus
// Cat: Twinky
let cats: Array<Cat> = []; // can only contain cats
let animals: Array<Animal> = []; // can only contain animals
// ERROR
// property `purrFactor` of Cat. Property not found in Animal
// cats = animals;
// same ERROR
// animals = cats;
End of story for Flow
My recommendation