Gian Marco Toso
Drinking coffee and saving the world. Software Engineer and professional geek
How I learned to stop worrying and love strong typings
Gian Marco Toso
@gianmarcotoso
gianmarcotoso
gianmarcotoso.com
polarityb.it
Software Engineer, The Pirate I Was Meant To Be
Born and raised in Turin, Italy
@gianmarcotoso
gianmarcotoso
gianmarcotoso.com
polarityb.it
MSc in Computer Engineering
Self Employed Software Engineer
Javascript and PHP Developer
Docker
PHP/Laravel
"It was working on my machine!"
The monolith is here to stay
NodeJS/TypeScript
Seriously, it's awesome!
React + Redux
The Flux Capacitor!
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript
- Official TypeScript Definition
class Person {
    constructor(name) {
        this.name = name
        this.steps = 0
    }
    walk(steps) {
        this.steps += steps
    }
    getSteps() {
        return this.steps
    }
}interface CanWalk {
    walk(steps: number): void
    getSteps(): number
}
class Person implements CanWalk {
    public name: string
    protected steps: number
    constructor(name) {
        this.name = name
        this.steps = 0
    }
    walk(steps: number): void {
        this.steps += steps
    }
    getSteps(): number {
        return this.steps
    }
}interface JSONSerializable {
    toJSON(): object
}
class SomeComplexObject implements JSONSerializable {
    /* ... */
}
function log(
    message: string, 
    payload: JSONSerializable
) { /* ... */ }More readable, better structured code
Errors stand out immediately
VSCode Integration + Intellisense
Consider a simple React Component
import React from 'react'
import * as PropTypes from 'prop-types'
class Image extends React.Component {
    static propTypes = {
        source: PropTypes.string.isRequired,
        size: PropTypes.arrayOf(PropTypes.number).isRequired
    }
    render() {
        const { source, size } = this.props
        const [ width, height ] = size
        const style = { width, height }
        return (
            <img 
                style={style}
                src={source}
            />
        )
    }
}
export default ImageFirst issue: propTypes
static propTypes = {
    source: PropTypes.string.isRequired,
    size: PropTypes.arrayOf(PropTypes.number).isRequired
}Checked at runtime (only in dev mode)
If the type is wrong, we'll see it at runtime within the browser's console
Wouldn't it be better if we knew right away?
Second issue: code completion
render() {
    const { source, size } = this.props
    const [ width, height ] = size
    const style = { width, height }
    // ...
}Our editor has no way of knowing how the `props` object or the `size` is made, and cannot help us.
The `style` object could have any member, the editor doesn't know that we want it to be passed to a components' `style` prop.
What does it look like?
import React from 'react'
import { CSSProperties } from 'react'
import { ImageProps } from './ImageProps'
class Image extends React.Component<ImageProps> {
    render() {
        const { source, size } = this.props
        const [ width, height ] = size
        const style: CSSProperties = { width, height }
        return (
            <img 
                style={style}
                src={source}
            />
        )
    }
}
export default ImageLet's take a look
// Size.ts
export type Size = [number, number]
// ImageProps.ts
interface ImageProps {
    source: string
    size: Size
}
export { ImageProps }By defining how the component's props are shaped using a TS Interface, we are moving the prop type check at compile-time rather than at run-time.
Intellisense to the rescue
The editor now knows exactly what we are working with (and we can even document it nicely with JSDoc!)
When using TypeScript with ReactJS, we can define the structure of both the component's Props and the component's State using interfaces.
Interfaces will make the component easier to work with, and can even be used as part of the component's documentation!
Best of all, if we do something wrong we'll know it straight away and not later, while running the app in our browser
Just like with React, we can use TypeScript to enhance our Redux Developer experience
Redux comes with TypeScript typings built-in, so we have TS support literally out the box!
Action Types can be defined as literal enums:
enum CounterActionsTypes {
    INCREMENT = 'COUNTER@INCREMENT',
    RESET = 'COUNTER@RESET'
}Actions can be shaped as interfaces
interface CounterAction {
    type: CounterActionTypes
    payload?: any
}Action Creators are function returning a specific type of Action
const increment: ActionCreator<CounterAction> = function() {
    return {
        type: CounterActionTypes.INCREMENT
    }
}
const reset: ActionCreator<CounterAction> = function() {
    return {
        type: CounterActionTypes.RESET
    }
}Our state can be defined as an interface
interface CounterState {
    count: number
}
const defaultState: CounterState = {
    count: 0
}Our reducer is a pure function, returning a specific type of state
const counterReducer: Reducer<CounterState> = (
	state: CounterState = defaultState,
	action: CounterAction
) => {
	switch (action.type) {
		case CounterActionTypes.INCREMENT: {
			return {
				...state,
				count: state.count + 1
			}
		}
		case CounterActionTypes.RESET: {
			return {
				...state,
				count: defaultState.count
			}
		}
		default: {
			return state
		}
	}
}Our store also has a strong definition
interface ApplicationState {
	counter: CounterState
}
const reducers: ReducersMapObject = {
	counter: counterReducer
}
const store: Store<ApplicationState> = 
    createStore<ApplicationState>(combineReducers(reducers))
Many libraries include their .d.ts definitions inside their main npm package, supporting TypeScript out of the box
For those that don't, try:
user@machine$ npm install @types/<library-name>
# npm install @types/react
# npm install @types/react-dom
# npm install @types/react-reduxUsing TypeScript in an existing project is possible - although a little bit tedious
We "just" need to add TypeScript to our toolchain and change the extensions of (all?) our files from js(x) to ts(x)
Then we need to fix all errors TypeScript is going to show us, for each of our files!
# ... make a branch (you'll break everything :P)
user@machine$ git checkout -b typescript-integration
# ... add the required packages and some types
user@machine$ yarn add -D typescript ts-loader @types/react @types/react-dom 
# ... initialize TypeScript
user@machine$ npx tsc --init --target es2016 --module es2015 --jsx preserve --moduleResolution\
node --allowSyntheticDefaultImports --allowJs
1. Go to your React project's root folder and...
2. Edit your Webpack configuration
//...
    module: {
	rules: [{ 
            test: /\.tsx?/, 
            exclude: /node_modules/, 
            use: ['babel-loader', 'ts-loader'] 
        }]
    },
    resolve: {
	extensions: ['.js', '.jsx', '.ts', '.tsx'],
    }
//...3. Change your extensions from .js(x) to .ts(x)
.tsx is required to use the JSX syntax
Thank you!
By Gian Marco Toso
Slides for my talk at the 2017 WebAppConf in Torino
Drinking coffee and saving the world. Software Engineer and professional geek