神刀安全网

Flow vs. Typescript: type systems for Javascript

Part I: Introduction

Why using type systems?

IMHO type systems make code easier to maintain

type annotations

  • can make code more readable
  • can make code easier to analyse
  • can allow for reliable refactoring
  • can allow for generally better IDE support
  • can catch errors early

Most important single use case for me

JSON style data structures

  • REST payload
  • config files
  • objects from and to database

as a close second place: find usages

TypeScript

ease of use and tool support over soundness

Flow

soundness, no runtime exceptions as goal

  • http://flowtype.org/
  • By Facebook
  • Flow is a static type checker, designed to quickly find errors in JavaScript applications
  • Not a compiler, but checker
  • Works without any type annotations
  • Very good at inferring types
  • If present, type annotations can very easily be removed by babel for runtime

Part II: Comparison

aka what I find most important

Basics

TypeScript

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}`;     } } 

Flow

 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}`;     } }  

Right, pretty much the same

Those basic features help with documentation, refactoring, and IDE support

Non-Nullable Types

Talking about correctness

TypeScript

 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

Flow

 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?

Flow does not infer string as the return type

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(); }  

Non-nullable types

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 )

Generics

aka Parametric Types

might be a bit scary…

Consider this type hierarchy

 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; } 

Generic Type information

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'));            

Up to this point this pretty much works in Flow and TypeScript the same way …

… but wait

TypeScript

 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 

Flow

 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

Why?

  • TypeScript
    • parametric types are compatible if the type to assign from has a more special type parameter
    • seems most intuitive
    • allows for obviously wrong code, though
  • Flow
    • using generic types you can choose from invariant (exact match), covariant (more special), and contravariant (more common)
    • Array in Flow has an invariant parametric type
    • more expressive
    • harder to understand

Part III: Epilogue

Should I use a type checker?

My recommendation

  • if your project does not live for long: no
  • if your project is really simple: no
  • if there is a chance you will need to refactor the thing: yes
  • if your system is very important or even crucial for the success of your company: yes
  • if people enter or leave your team frequently: yes

Wrap-Up

  • TypeScript and Flow have influenced each other heavily
  • Basic typings are pretty similar
  • Both also support React
  • Many more constructs like union, intersection, and array types in both
  • Flow can even understand TypeScript declaration files
  • TypeScript is a compiler, Flow is a checker
  • Flow shoots for soundness, TypeScript for tool support
  • Flow has non-nullable types as defaults
  • Generics in TypeScript are easier, but less expressive
  • Flow’s type system is generally more expressive
  • Flow written in OCaml, Typescript in Typescript

Thank you!

Questions / Discussion

Oliver Zeigermann / @DJCordhose

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Flow vs. Typescript: type systems for Javascript

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址