Why Static Type Checking is Better

Post on 15-Jul-2015

342 views 4 download

transcript

Why Static Type Checking is Better@AndrewRotaJavaScript Engineer,

With JavaScript...anything is possible

@AndrewRota | #empirejs 2/48

Change all the types...

@AndrewRota | #empirejs

var x; // x starts undefinedtypeof x === 'undefined'

x = 5;  // now it's is a numbertypeof x === 'number'

x = 'five'; // now it's a stringtypeof x === 'string'

x = true;  // now it's a booleantypeof x === 'boolean'

x = {value: 'five'}; // now it's an objecttypeof x === 'object'

JS

3/48

We have types, but they're not static.(No type is known or declared at compile time)

@AndrewRota | #empirejs 4/48

7 Types in JavaScript

@AndrewRota | #empirejs

Boolean Number String Object

Symbol Null Undefined

5/48

Most code has type expectations...we just don't always acknowledge it.

@AndrewRota | #empirejs

function add(arr) {    var sum = 0;    for (var i = 0; i < arr.length; i++) {        sum += arr[i];    }    return sum;}

add([2,3]); // returns 5 as expectedadd(['foo', 'bar']);  // returns "0foobar" (expected?)add(null);  // Throws exception: cannot read prop 'length' of null

JS

6/48

What to do?

@AndrewRota | #empirejs 7/48

Ad Hoc Runtime Checks

@AndrewRota | #empirejs

function add(arr) {    if (!Array.isArray(arr)) return;    var sum = 0;    for (var i = 0; i < arr.length; i++) {        if (typeof arr[i] !== 'number') return;        sum += arr[i];    }    return sum;}

JS

8/48

Ad Hoc Runtime Checks

@AndrewRota | #empirejs

function add(arr) {    if (!Array.isArray(arr)) throw('not an array');    var sum = 0;    for (var i = 0; i < arr.length; i++) {        if (typeof arr[i] !== 'number') throw('not a number');        sum += arr[i];    }    return sum;}

JS

9/48

Type Annotations

@AndrewRota | #empirejs

/** * Add all numbers in an array * * @param {number[]} * @return {number} */function add(arr) {    var sum = 0;    for (var i = 0; i < arr.length; i++) {        sum += arr[i];    }    return sum;}

JS

10/48

Type Annotations

Explicit typing...without any checks.

@AndrewRota | #empirejs

/** * Add all numbers in an array * * @param {number[]} * @return {number} */function add(arr) {    var sum = 0;    for (var i = 0; i < arr.length; i++) {        sum += arr[i];    }    return sum;}

JS

11/48

Code Reviews !== Type Checks

@AndrewRota | #empirejs 12/48

Type Checking in JavaScript

@AndrewRota | #empirejs 13/48

ActionScriptEarly 2000s | Partially conformed to ECMAScript 4

@AndrewRota | #empirejs

private function add(arr:Array):int{    var sum:int = 0;    for (var i:int = 0; i < arr.length; i++) {        sum += arr[i];    }    return sum;}

AS

14/48

Closure Compiler~2009

@AndrewRota | #empirejs

/** * Add all numbers in an array * * @param {number[]} * @return {number} */function add(arr) {    var sum = 0;    for (var i = 0; i < arr.length; i++) {        sum += arr[i];    }    return sum;}

JS

15/48

TypeScript2012 | Compiles to JavaScript, optional static typing

@AndrewRota | #empirejs

function add(arr:Array<number>):number{    var sum:number = 0;    for (var i:number = 0; i < arr.length; i++) {        sum += arr[i];    }    return sum;}

TS

16/48

Flow2014 | Compiles to JavaScript, optional static typing

@AndrewRota | #empirejs

/* @flow */function add(arr:Array<number>):number{    var sum:number = 0;    for (var i:number = 0; i < arr.length; i++) {        sum += arr[i];    }    return sum;}

FLOW

17/48

Flow Comments2015 | Alternative to a transpile step

@AndrewRota | #empirejs

/* @flow */function add(arr/*:Array<number>*/)/*:number*/{    var sum/*:number*/ = 0;    for (var i/*:number*/ = 0; i < arr.length; i++) {        sum += arr[i];    }    return sum;}

JS

18/48

Released Runtime Env. No Transpile Null Checking ES6

Closure Compiler 2009 Java ✓ X Some

TypeScript 2012 JavaScript X X Some

Flow 2014 OCaml X ✓ Some

Flow Comments 2015 OCaml ✓ ✓ Some

@AndrewRota | #empirejs 19/48

Adding Gradual Type Checks

@AndrewRota | #empirejs 20/48

Step 1: Choose a Type Checker

Step 2: Set Up a Transpile Step

Step 3: Add Type Annotations

@AndrewRota | #empirejs 21/48

Step 1: Choose a Type Checker

Step 2: Set Up a Transpile Step

Step 3: Add Type Annotations

@AndrewRota | #empirejs 22/48

TypeScript Flow

TypeScript vs. Flow

@AndrewRota | #empirejs

Released 2012Written in JS: any OSCommunity-provideddeclaration filesAddtional transpiled features(defaults, overloads)

···

·

Released 2014Written in OCaml: OSX, LinuxBuilt-in null handling.Comment-only syntaxavailable

····

23/48

Step 1: Choose a Type Checker

Step 2: Set Up a Transpile Step

Step 3: Add Type Annotations

@AndrewRota | #empirejs 24/48

Setting Up Flow

1. Install Flow from flowtype.org

2. Add transformer ( JSX or Babel ) to your build

@AndrewRota | #empirejs 25/48

Using Flow

1. Run flow check

2. Run build with transformer.

@AndrewRota | #empirejs

Check → Transform

26/48

Using Flow

@AndrewRota | #empirejs 27/48

Setting Up TypeScript

Install TypeScript with npm i ‐g typescript

@AndrewRota | #empirejs 28/48

Using TypeScript

Run tsc myFile.ts

@AndrewRota | #empirejs 29/48

Using TypeScript

@AndrewRota | #empirejs 30/48

Step 1: Choose a Type Checker

Step 2: Set Up a Transpile Step

Step 3: Add Type Annotations

@AndrewRota | #empirejs 31/48

Type InferenceSome of your work's already done!

Flow: property length: Property not found in Number

TypeScript: Property 'length' does not exist on type 'number'

@AndrewRota | #empirejs

var x = 1;x.length;

JS

32/48

Adding Basic Types

Flow: number, string, boolean, void, Array, Function, Object, mixed, any

TypeScript: number, string, boolean, void, Array, Function, Object, any, enum

@AndrewRota | #empirejs

var x:string = 'test'; TS/FLOW

33/48

Arrays

@AndrewRota | #empirejs

var list:number[] = [1,2,3];

var anotherList:Array<number> = [1,2,3];

TS/FLOW

34/48

Union TypesThisType | ThatType

@AndrewRota | #empirejs

var x: number | string = 0;x = 'foo';

TS/FLOW

35/48

Null ChecksFlow has the advantage here

Flow: property x: Property cannot be accessed on possibly null value

TypeScript:  no error

@AndrewRota | #empirejs

var x = null;x.foo;

JS

36/48

FunctionsBoth arguments and return values (the function itself)

@AndrewRota | #empirejs

function helloWorld(name: string):string {   return 'Hello, ' + name;}function addExclamation(sentence: string):string {    return sentence + '!';}addExclamation(helloWorld('EmpireJS'));

TS/FLOW

37/48

Object Literals

@AndrewRota | #empirejs

function doSomething(modelObject: {title: string}) {   return modelObject.title;}

doSomething({title: 'My Object!', id: 2, flag: true});

TS/FLOW

38/48

Interfaces

External interfaces via declaration files→ Find TypeScript declarations at definitelytyped.org

@AndrewRota | #empirejs

interface Model {    title: string}function doSomething(modelObject: Model) {   return modelObject.title;}

doSomething({title: 'My Object!', id: 2, flag: true});

TS/FLOW

39/48

And there's more!

@AndrewRota | #empirejs

ClassesModulesNullable TypesGenericsPolymorphism

·····

40/48

But is it worth it?

@AndrewRota | #empirejs 41/48

Catch More Bugs at Compile Time

Flow: null: This type is incompatible with string

@AndrewRota | #empirejs

function helloWorld(name:string) {    return 'Hello, ' + name;}

helloWorld('EmpireJS');helloWorld(null);        

FLOW

42/48

Self-Document Code Behavior

@AndrewRota | #empirejs

function flatten (input, shallow, strict) {}        

JS

function flatten (    input: Array<any>,    shallow: boolean,    strict: boolean): Array<any> {}        

TS/FLOW

source: http://flowtype.org/docs/underscore.html#_

43/48

Easier to Reason About Code Flow

@AndrewRota | #empirejs

In: Number

Out: String↗

In: String

Out: Object↗

In: Object

Out: Boolean

44/48

- Bertrand Meyer

Correctness

“ The ability of software products to perform their exact tasks, asdefined by their specification.

@AndrewRota | #empirejs 45/48

Tooling

IntelliJ

Sublime

@AndrewRota | #empirejs 46/48

- TypeScript and the Road to 2.0

And someday it might be in JavaScript...

“ The TypeScript team is [...] looking forward to working together goingforward and creating the best tools we can for the JavaScript community.In the long term, we will also be working to fold the best features ofthese tools into ECMAScript, the standard behind JavaScript.

@AndrewRota | #empirejs 47/48

Thanks!

twitter @andrewrota

github github.com/andrewrota