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 = undefined
Types 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') // x
Types 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() // x
Types 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) // x
Types 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 works
Types 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