Here are some notes about TypeScript in React.
They come from the book The Road to React by Robin Wieruch.
Setup
TypeScript is a programming language developed by Microsoft that adds static typing with optional type annotations to JavaScript.
- install TypeScript and its dependencies:
npm install typescript @types/react @types/react-dom --save-dev
- add TypeScript configurations files
touch tsconfig.json tsconfig.node.json
- one for the browser environment
- one for the Node environment
- rename JavaScript files:
mv src/main.jsx src/main.tsx mv src/App.jsx src/App.tsx
- change references in HTML files (
.jsx
->.tsx
) - install a TypeScript plugin for your IDE to see red lines under all the values where TypeScript definitions are missing
Assertion
Assertion with as
(e.g. when you are certain there is an HTML element):
document.getElementById('root') as HTMLElement
Type safety
A function's input (and optionally output) has to be type safe:
const useStorageState = (
key: string,
initialState: string
): [string, (newValue: string) => void] => {
…
}
Here, useStorageState
:
- expect two arguments as string primitives
- return an array with:
- a first value of type
string
(the current state) - a second value of type
function
(the state updater function)- that returns nothing (
void
) - and takes a new state (
newValue
) of typestring
- that returns nothing (
- a first value of type
Type inference works most of the time for React hooks. TypeScript can work out a variable's type without it having a type annotation:
const [value, setValue] = React.useState('React');
// value is inferred to be a string
// setValue only takes a string as argument
TypeScript generics
TypeScript generics let you specify a type that can change depending on the usage:
type User<StatusOptions> = {
name: string;
status: StatusOptions;
};
const user: User<'online' | 'offline'>;
const user: User<'online' | 'offline' | 'idle'>;
StatusOptions
is called a type variable and User
is said to be a generic type.
It's the TypeScript equivalent of functions, a JavaScript-like syntax would look like this:
type User = (StatusOption) => {
return {
name: string;
status: StatusOptions;
}
}
A very common usage is having a function that returns the same type as its argument:
function identity<ArgType>(arg: ArgType): ArgType {
return arg;
}
In React, useState
itself takes a type variable called S
. So, if the initial state would be null
initially, we can use:
const [value, setValue] = React.useState<string | null>(null);
// value has to be either a string or null
// setValue only takes a string or null as argument
Defining types outside of components
type Story = {
objectID: string;
url: string;
title: string;
author: string;
num_comments: number;
points: number;
};
type ItemProps = {
item: Story;
onRemoveItem: (item: Story) => void;
};
const Item = ({ item, onRemoveItem }: ItemProps) => (
…
);
item
is of type Story
and onRemoveItem
takes an item
of type Story
as an argument and returns nothing.
Alternative way with React.FunctionComponent
(or React.FC
):
const Item: React.FC<ItemProps> = ({ item, onRemoveItem }) => (
<li>
…
</li>
);