Typesafe(ish) React

Typesafe(ish) React

Static type-checking via tools like TypeScript or Flow can help reveal implementation errors before the app goes down. This presentation looks at what these tools are—and aren't—and how you can use them to build safer, saner React applications.

0b7fb38ae0407a97f5a342ebbcc288f7?s=128

RJ Zaworski

October 10, 2018
Tweet

Transcript

  1. 2.

    “ Types ...tell the compiler or interpreter how the programmer

    intends to use the data” (https://en.wikipedia.org/wiki/Data_type, http://bit.ly/2C09A0w)
  2. 3.

    “ Type safety ...the extent to which a programming language

    discourages or prevents type errors” > const sayHello = "I'm a string."; > sayHello(); TypeError: sayHello is not a function (https://en.wikipedia.org/wiki/Type_safety)
  3. 4.

    Type checks ★ Static v. dynamic (when is check made?)

    ★ Strong v. weak (how strict is it?) Dynamic Static Weak JavaScript C (sort of) Strong Python, Ruby Flow, Reason, TypeScript
  4. 7.
  5. 8.
  6. 12.

    Why TypeScript? Good! ★ Superset of JS ★ ESNext included

    * ★ Performance ★ Community But... ★ Superset of JS ★ Integration with existing projects ★ Consider alternatives * YMMV
  7. 13.

    Hello, world! 1. Install $ npm install -g typescript 2.

    Compile $ tsc --strict point.ts 3. Run $ node point.js { x: 3, y: 4 } type Point = { x: number, y: number, }; const add = (p1: Point, p2: Point): Point => ({ x: p1.x + p2.x, y: p1.y + p2.y, }); const p: Point = { x: 1, y: 1 }; const o: Point = { x: 2, y: 3 }; console.log(add(p, o)); point.ts
  8. 14.

    Hello, world! Even good programmers do bad things... $ tsc

    point.ts point.ts:8:3 - error TS2339: Property 'z' does not exist on type 'Point'. 8 p.z = 42; ~ type Point = { x: number, y: number, }; const p: Point = { x: 1, y: 1 }; p.z = 42; point.ts
  9. 15.

    Interfaces ★ Define data shape ★ Extensible interface Bounds {

    readonly w: number, // width readonly h: number, // height area(): number, } function square (a: number) { return { h: a, w: a, area: () => a * a, }; } function perimeter (b: Bounds) { return 2 * (b.w + b.h); } interface.ts h w area()
  10. 16.

    Generics ★ Reusable ★ Type-independent type Circle = Bounds &

    { readonly r: number, } function circle (r: number) { const area = () => Math.PI * r * r; return { r, h: r + r, w: r + r, area }; } const mapper = <T, U>(f: (t: T) => U) => (ts: T[]) => ts.map(f); const circleMapper = mapper<number, Circle>(circle); const circles = circleMapper([1, 2, 3]); generics.ts h w r
  11. 17.
  12. 18.

    Getting started 1. Scaffold $ npx create-react-app myapp \ --scripts-version=react-scripts-ts

    2. Install some dependencies $ npm i redux $ npm i react-redux 3. And some @types $ npm i @types/react-redux
  13. 20.

    Stateless Consider… interface StatelessComponent<P> { (props: P, context?: any): ReactElement<any>;

    // ... }; type SFC<P> = StatelessComponent<P> import * as React from 'react'; type GameProps = { outcome: string, shipsSunk: number, ]; const GameView: React.SFC<GameProps> = (props) => ( <div> outcome: {props.outcome}<br /> shipsSunk: {props.shipsSunk}<br /> </div> ); GameView.ts
  14. 21.

    Stateful Consider… class Component<P, S> { // ... state: readonly<S>;

    render(): ReactNode; } class App extends React.Component<{}, { outcome: string, shipsSunk: number, }> { state = { outcome: 'PENDING', shipsSunk: 0, }; render() { return <GameView {...this.state} />; } } App.ts
  15. 22.

    Events DOM types? interface MouseEvent<T = Element> extends SyntheticEvent<T> {

    clientX: number; clientY: number; // ... } onClick = (e: React.MouseEvent) => fireCannonAt({ x: e.clientX, y: e.clientY, }); render() { return ( <div onClick={this.onClick}> <GameView {...this.state} /> </div> ); } App.ts