An overview of Typescript, FlowType and Elm
Types in JS
Things we expect from a sensible type system, and how Typescript and Flow implement them.
And a little theory -
Type annotations should be:
Types in JS
Types in JS
// Typescript
let n: number = 12;
let str: string = "abc";
let t: boolean = true;
let x: null = null;
let y: undefined = undefined;// @flow
let n: number = 12;
let str: string = "abc";
let t: boolean = true;
let x: null = null;
let y: void = undefined;// Typescript
let arr1: number[] = [1,2,3];
let arr2: Array<number> = [1,2,3];
// The tuple
let tup1: [string, number, boolean];
tup1 = ["Abhi", 92, false]// @flow
let arr1: number[] = [1,2,3];
let arr2: Array<number> = [1,2,3];
// The tuple
let tup1: [string, number, boolean];
tup1 = ["Abhi", 92, false]
Types in JS
// Typescript
let notSure: any;
notSure = 1
notSure = "abc"
notSure = null
notSure = undefined// @flow
let notSure: any;
notSure = 1
notSure = "abc"
notSure = null
notSure = undefinedTypes in JS
Types in JS
Type annotations are -
For both Typescript and Flow
The syntax is also very similar
Types in JS
Typescript-
Trying out:
https://www.typescriptlang.org/play/index.html
Flow -
Trying out:
https://flow.org/try/
Types in JS
Typescript-
Flow -
Types in JS
// Typescript
let num: number;
num = null  // No error by default
// Use the --strictNullChecks flag 
// to catch these errors// @flow
let num: number;
num = null  // Error
Types in JS
Types in JS
// Typescript
interface Score {
  player: string;
  runs: number;
}
let s1:Score, s2:Score, s3:Score;
s1 = { player: 'Abhi', runs: 20 } // √
s2 = { player: 'Abhi' }           // x
s3 = { player: 'Abhi', runs: 20,  // x 
       wickets: 2 }// @flow
interface Score {
  player: string,  // <- comma here
  runs: number
}
let s1:Score, s2:Score, s3:Score;
s1 = { player: 'Abhi', runs: 20 } // √
s2 = { player: 'Abhi' }           // x
s3 = { player: 'Abhi', runs: 20,  // √
       wickets: 2 }
Types in JS
// Typescript
var obj = {
  foo: 1
}
obj.bar = 123 // x
obj.foo = 456 // √// @flow
var obj = {
  foo: 1
}
obj.bar = 123 // x
obj.foo = 456 // √Types in JS
Types in JS
// Typescript
function incr(x: number): number {
  return x+1
}
incr(2)    // √
incr('2')  // x// @flow
function incr(x: number): number {
  return x+1
}
incr(2)    // √
incr('2')  // xTypes in JS
// Typescript
function incr(x: number): number {
  return x+1
}
incr(2)    // √
incr('2')  // x
incr()     // x// @flow
function incr(x: number): number {
  return x+1
}
incr(2)    // √
incr('2')  // x
incr()     // xTypes in JS
// Typescript
// x is optional
function incr(x?: number): number {
  if (x == undefined) return 1;
  return x+1
}
incr(1)     // √
incr('1')   // X
incr()      // √
incr(null)  // X
function incr1(x: number): number {
  return x+1  // Error: possibly undefined
}
// @flow
// x is optional
function incr(x?: number): number {
  return x+1
}
incr(2)    // √
incr('2')  // x
incr()     // √
incr(null) // xTypes in JS
// Typescript
function incr(x: number): number {
  if (x == 1) return null;  // Error
  return x+1
}
// Error only with 
// --strictNullChecks flag
// @flow
function incr(x: number): number {
  if (x == 1) return null; // Error
  return x+1
}
Types in JS
// Typescript
function onClick(callback: (element: string) => string){
  callback('.my-class')
}
onClick(function (el) {
  return 'ok:' + el
})
// onClick takes ONE callback function
// The callback function takes a string argument 
// and returns a string
// This can be made to look better// @flow
Typescript
Types in JS
// Typescript
type CallBackType = (element: string) => string
function onClick(callback: CallBackType): void{
  callback('div')
}
onClick(function (el) {
  return 'ok'
})
// @flow
Types in JS
// Typescript
type Elem = string
type Status = string
type CallBackType = (element: Elem) => Status
function onClick(callback: CallBackType): void{
  callback('div')
}
onClick(function (el) {
  return 'ok'
})
// @flow
Types in JS
//
// @flow
function onClick(callback: (string) => string){
  callback('div')
}
onClick(function (el) {
  return 'ok'
})
Flow
Types in JS
//
// @flow
type Elem = string
type Status = string
type CallbackType = (Elem) => Status
function onClick(callback: CallbackType): void{
  callback('div')
}
onClick(function (el) {
  return 'ok'
})
Flow
Types in JS
// Typescript
// Valid
type FType1 = (x: number) => number
type Ftype2 = (x: number, str: string) => number  
type Ftype3 = (number) => number
type Ftype4 = (number, string) => number
// Invalid. specify the variables
type Ftype99 = (number, number) => number
// Valid
type Ftype5 = (number, Ftype2) => number
type Ftype6 = (number, Ftype2) => Ftype4
// @flow
// Valid
type FType1 = (x: number) => number
type Ftype2 = (x: number, str: string) => number  
type Ftype3 = (number) => number
type Ftype4 = (number, string) => number
// Also valid
type Ftype99 = (number, number) => number
// Valid
type Ftype5 = (number, Ftype2) => number
type Ftype6 = (number, Ftype2) => Ftype4
Types in JS
// Typescript
// The Function type
function onClick2(callback: Function) {
  callback();
}
// @flow
function onClick2(callback: Function) {
  callback('span');
}
Types in JS
More:
Types in JS
Useful when -
Types in JS
// Typescript
type NBT = number | boolean | string
function toString(x: NBT): string {
  return String(x)
}
// @flow
type NBT = number | boolean | string
function toString(x: NBT): string {
  return String(x)
}
Types in JS
// Typescript
function leftPad(x: number | string  ) {
  let lp: string
  
  if (typeof (x) == "number") {
    lp = String(x)
  } else {
    lp = x
  }
  let lp1: string = lp + ' px';
  actualLeftPadding(lp1);
}
// @flow
Types in JS
// Typescript
function leftPad(x: number | string | null ) {
  let lp: string
  
  if (typeof (x) == "number") {
    lp = String(x)
  } else {
    lp = x  // Error here
  }
  let lp1: string = lp + ' px';
  actualLeftPadding(lp1);
}
// @flow
Types in JS
// Typescript
function head(list: string[]): string {  
  return list[0]  // undefined for []
}
// @flow
function head(list: string[]): string {  
  return list[0]  // undefined for []
}
Types in JS
// Typescript
type MaybeString = string | null | undefined
function head(list: string[]): MaybeString {  
  return list[0]  // undefined for []
}
// @flow
type MaybeString = string | void;
function head(list: string[]): MaybeString {  
  return list[0]  // undefined for []
}
Types in JS
// Typescript
type MaybeString = string | null | undefined
function head(list: string[]): MaybeString {  
  return list[0]
}
function topScorer(): string {
  let list: string[];
  // list = fetch(...)
  return head(list); // Error here. 
}// @flow
Types in JS
// Typescript
type MaybeString = string | null | undefined
function head(list: string[]): MaybeString {  
  return list[0]
}
function topScorer(): string {
  let list: string[] = [];
  // list = fetch(...)
  let top: MaybeString = head(list);
  if (top == null) return '';
  if (top == undefined) return '';
  return top;
}
// @flow
function head(list): ?string {
  return list[0]
}
function topScorer(): string {
  let str: ?string = ''
  let list: string[] = []
  
  str = head(list)
  
  if (str == null) return ''
  return str
}
Types in JS
// Typescript
// Notice the type of success
type HttpSuccess = { success: true,  data:  string }
type HttpFail    = { success: false, error: string }
type HttpResponse = HttpSuccess | HttpFail
function handleResponse(response: HttpResponse) {
  let data: string;
  let err: string;
  if (response.success) 
  {
    data = response.data  // √
    console.log(data)
  } 
  else 
  {
    err = response.error  // √
    console.log(err)
  }
}
// @flow
// <= Exact same code worksTypes in JS
-- ELM
type User = Anonymous | Named String
userPhoto : User -> String
userPhoto user =
  case user of
    Anonymous ->
      "anon.png"
    Named name ->
      "users/" ++ name ++ ".png"
  
// @flow
Types in JS
-- ELM
type Result error value
  = Err error
  | Ok value
view : String -> Html msg
view userInputAge =
  case String.toInt userInputAge of
    Err msg ->
      span [class "error"] [text msg]
    Ok age ->
      text "OK!"
// @flow
Types in JS
Useful when -
Types in JS
// Typescript
function identity<T>(x: T): T {
  return x
}
function identity1(x: any): any {
  return 123
}
let str: string = identity<string>("hello") // √
let str1: string = identity("hi") // T is inferred
// @flow
function identity<T>(x: T): T {
  return x
}
Types in JS
// Typescript
function reverse<T>(arr: T[]): T[] {
  return arr.reverse()
} 
// @flow
function reverse<T>(arr: T[]): T[] {
  return arr.reverse()
} 
Types in JS
// Typescript
// type MaybeString = string | null | undefined
type Maybe<T> = T | null | undefined;
function head(list: string[]): Maybe<string> {  
  return list[0]
}
function topScorer(): string {
  let list: string[] = [];
  // list = fetch(...)
  let top: Maybe<string> = head(list);
  if (top == null) return '';
  if (top == undefined) return '';
  return top;
}
// @flow
Types in JS
// Typescript
type HttpSuccess<T1> = { success: true,  data: T1 }
type HttpFail<T2>    = { success: false, error: T2 }
type MyData = { name: string, score: number }
type MyError = { code: number, msg: string }
type HttpResponse = HttpSuccess<MyData> | HttpFail<MyError>
function handleResponse(response: HttpResponse) {
  let data: MyData;
  let err: MyError;
  if (response.success) 
  {
    data = response.data  // √
    console.log(data)
  } 
  else 
  {
    err = response.error  // √
    console.log(err)
  }
}
// @flow
Types in JS
Typescript
Flow
Recommendations
Other comments