Best practices for using Typescript with React

Christopher Diggins
Jun 5, 2018 · 9 min read
Type theory for the win!!!

Finding type definitions for a library

"@types/jest": "^22.0.1",
"@types/node": "^9.3.0",
"@types/react": "^16.0.34",
"@types/react-dom": "^16.0.3",
"@types/redux-logger": "^3.0.5"

Compile-time validation of properties and state fields

import * as React from ‘react’;export interface CounterDisplayProps {
value: number;
label: string;
}
export class CounterDisplay extends React.PureComponent<CounterDisplayProps> {
render(): React.ReactNode {
return (
<div>
The value of {this.props.label} is {this.props.value}
</div>
);
}

Components as classes or functions

Component Classes

interface ComponentClass<P = {}> {
new (props: P, context?: any): Component<P, ComponentState>;
}

Stateless Components (SFC)

interface StatelessComponent<P = {}> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
}
type SFC<P = {}> = StatelessComponent<P>;

Pure and Non-Pure Components

Stateful Components can (and should) derive from React.PureComponent

import * as React from ‘react’;
export interface StatefulCounterProps {
label: string;
}
// By making state a class we can define default values.
class StatefulCounterState {
readonly count: number = 0;
};
// A stateful counter can be a React.PureComponent
export class StatefulCounter
extends React.PureComponent<StatefulCounterProps, StatefulCounterState>
{
// Define
readonly state = new State();
// Callbacks should be defined as readonly fields initialized with arrow functions, so you don’t have to bind them
// Note that setting the state based on previous state is done using a callback.
readonly handleIncrement = () => {
this.setState((prevState) => {
count: prevState.count + 1 } as StatefulCounterState);
}
// We explicitly include the return type
render(): React.ReactNode {
return (
<div>
<span>{this.props.label}: {this.props.count} </span>
<button type=”button” onClick={this.handleIncrement}>
{`Increment`}
</button>
</div>
);
}
}

React Stateless Functional Components are not Pure Components

Typing higher-order components

The confusion of export default

HOCs that Inject Properties

Inner, Outer, and Injected Properties

The type intersection operator

interface LabelProp {
label: string;
}
interface ValueProp {
value: number;
}
// Has both a label field and a value field
type LabeledValueProp = LabelProp & ValueProp;

Defining properties for a wrapped component

interface MyProperties {
value: number;
}
class MyComponentBase extends React.PureComponent<MyProperties & InjectedIntlProps> {
// Now has intl as a property
// ...
}
export const MyComponent = injectIntl(MyComponentBase); // Has the type React.Component<MyProperties>;

The React-Redux connect function

Helping the React-Redux connect function infer types

Final Words

Acknowledgements

freeCodeCamp.org

This is no longer updated. Go to https://freecodecamp.org/news instead

Christopher Diggins

Written by

A software developer and programming language designer working at Clemex Technologies in Montreal. I like transforming complex problems into simple ones.

freeCodeCamp.org

This is no longer updated. Go to https://freecodecamp.org/news instead