why static type checking is better
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