Upgrade to Pro — share decks privately, control downloads, hide ads and more …

type safety + front-end code =

type safety + front-end code =

A brief motivation for the importance of static type safety in larger codebases. Comparison of different static type-checkers options for front-end code: TypeScript, Flow, Reason, Elm. Trade-offs and recommendations.

Kenneth Skovhus

June 15, 2017
Tweet

More Decks by Kenneth Skovhus

Other Decks in Programming

Transcript

  1. TYPE SAFETY IS THE EXTENT TO WHICH A PROGRAMMING LANGUAGE

    DISCOURAGES OR PREVENTS TYPE ERRORS.
  2. function Greeter({name}) { return ( <h1>Hello, {name}</h1> ); } Greeter.propTypes

    = { name: PropTypes.string }; REACT PROPTYPES EXCELLENT GATEWAY DRUG INTO STATIC TYPES ENFORCED COMPILE TIME INSTEAD OF RUNTIME?
  3. CAPTURE ERRORS COMPILE TIME SMARTER TOOLING (E.G. AUTO COMPLETION) MAKE

    REFACTORING LESS SCARY DOCUMENT THE INHERENT TYPES A SYSTEM A STATIC TYPE CHECKER SHOULD
  4. MICROSOFT TYPESCRIPT FIRST RELEASED 2012, ANDERS HEJLSBERG (C#) SUPERSET OF

    JAVASCRIPT (ES2016+) TYPE ANNOTATIONS, ENUMS, CLASS INTERFACES COMPILER / TYPECHECKER / BUNDLER LOTS OF LIBRARY DEFINITIONS USERS: ANGULAR 2, VS CODE, ...
  5. FIRST RELEASED 2014 TYPESCRIPT-LIKE ANNOTATIONS FOR JS (OPT-IN) ONLY A

    POWERFUL TYPE CHECKER USE BABEL OR * AS COMPILER, WEBPACK OR * AS BUNDLER USERS: FACEBOOK, REACT, REACT-NATIVE FACEBOOK FLOW
  6. function greeter(person) { return "Hello, " + person; } const

    user = [0, 1, 2]; document.bodi.innerHTML = greeter(user); PLAIN JS
  7. function greeter(person: string) { return "Hello, " + person; }

    const user = [0, 1, 2]; document.bodi.innerHTML = greeter(user); tsc greeter.ts greeter.ts(8,15): error TS2339: Property 'bodi' does not exist on type 'Document'. greeter.ts(8,35): error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'. TYPESCRIPT
  8. /* @flow */ function greeter(person) { return "Hello, " +

    person; } const user = [0, 1, 2]; document.bodi.innerHTML = greeter(user); FLOW flow check greeter-flow.js:3 3: return "Hello, " + person; ^^^^^^ array literal. This type cannot be added to 3: return "Hello, " + person; ^^^^^^^^^^^^^^^^^^ string greeter-flow.js:8 8: document.bodi.innerHTML = greeter(user); ^^^^ property `bodi`. Property not found in 8: document.bodi.innerHTML = greeter(user); ^^^^^^^^ Document
  9. function greeter(person: string) { return "Hello, " + person; }

    const user = "John"; document.body.innerHTML = greeter(user); EASY DEBUG-ABLE OUTPUT MATTERS! function greeter(person) { return "Hello, " + person; } const user = "John"; document.body.innerHTML = greeter(user); FLOW & TYPESCRIPT
  10. NEW LANGUAGE! PURE SCRIPT ELM IS JAVASCRIPT + TYPES THE

    ANSWER? EXISTING LANGUAGE 2 JS! SCALA.JS CLOSURESCRIPT BUCKLESCRIPT (OCAML)
  11. FIRST APPEARED 2012 REASON: SYNTAX & TOOLCHAIN FOR OCAML OCAML:

    EXCELLENT TYPE INFERENCE (NO TYPE DECLARATION BLOAT) BUCKLESCRIPT: COMPILES OCAML TO FAST/SIMPLE JS VERY EARLY STAGES... POPULAR USERS: MESSENGER.COM (~30%) FACEBOOK REASON + BUCKLESCRIPT
  12. FIRST APPEARED 2012 PURELY FUNCTIONAL LANGUAGE DOMAIN-SPECIFIC STANDARD LIB FOR

    WEB APPLICATIONS SUPER USER FRIENDLY TOOLING & ECO SYSTEM THE ELM ARCHITECTURE POPULAR USERS: PREZI? ELM
  13. let greeter = fun name => "Hello, " ^ name;

    let user = [1, 2, 3]; /* Tried bs-webapi and bs-dom... */ REASON + BUCKLESCRIPT
  14. import Html exposing (text) greeter person = "Hello, " ++

    person main = text (greeter [0, 1, 2]) ELM elm make Greeter.elm -- TYPE MISMATCH --------------------------------------------------- Greeter.elm The argument to function `greeter` is causing a mismatch. 7| greeter [0, 1, 2]) ^^^^^^^^^ Function `greeter` is expecting the argument to be: String But it is: List number Detected errors in 1 module.
  15. TYPE SAFE FRONT-END CODE RECOMMENDATIONS? GREEN FIELD WEBSITE → FLOW

    / TYPESCRIPT OR ELM GREEN FIELD NODE PROJECT → FLOW / TYPESCRIPT GREEN FIELD REACT NATIVE → FLOW EXISTING CODEBASE (WEB, NODE, REACT NATIVE) → FLOW / TYPESCRIPT
  16. CONFIG REDUCER & ACTIONS REDUX DOCUMENT REDUCER & ACTIONS PUBLISHER

    REDUCER & ACTIONS USER REDUCER & ACTIONS … REDUCER & ACTIONS
  17. CONFIG REDUCER & ACTIONS + TYPES REDUX DOCUMENT REDUCER &

    ACTIONS + TYPES PUBLISHER REDUCER & ACTIONS + TYPES USER REDUCER & ACTIONS + TYPES … REDUCER & ACTIONS + TYPES
  18. REDUX USER/REDUCER.JS const initialState = { token: null, userId: null,

    }; function reducer(state = initialState, action) { switch (action.type) { case “USER/SET_USER_ID”: return { ...state, userId: action.id }; ...
  19. REDUX USER/REDUCER.JS /* @flow */ import type { Action }

    from ‘../types’; export type State = {| +token: ?string, +userId: ?number, |}; const initialState = { token: null, userId: null, }; function reducer(state: State = initialState, action: Action) { switch (action.type) { case “USER/SET_USER_ID”: return { ...state, userId: action.id }; ...
  20. function Greeter({name}) { return ( <h1>Hello, {name}</h1> ); } Greeter.propTypes

    = { name: PropTypes.string }; REACT PROPTYPES CODEMOD-PROPTYPES-TO-FLOW
  21. function Greeter({name}: Props) { return ( <h1>Hello, {name}</h1> ); }

    type Props = { name: ?string }; REACT PROPTYPES flow src/components/App.js:31 <Greeter name={[1, 2, 3]} /> ^^^^ props of React element `Greeter`. This type is incompatible... CODEMOD-PROPTYPES-TO-FLOW