TypeScript for React

TypeScript for React

majority of React projects will use TypeScript instead of JavaScript

static typing → better autocompletion and error detection

TypeScript for React

topics:

  • basic type declarations
  • type aliases and interfaces
  • parameter types and return types of functions
  • generics
  • type assertions

Static typing

data types may be specified explicitly by the developer or inferred by the development invironment

benefits:

  • better auto completion
  • better error detection

Static typing

example:

let names: Array<string> = [];

names.push('Alice');
names.push('Bob');

console.log(names[0].toUpperCase());

Playground

experiment with TypeScript online:

https://www.typescriptlang.org/play

Data types and type declarations

Data types and type declarations

data types that we'll use:

  • boolean
  • number
  • string
  • array
  • object

Variable types

variable types can be specified when declaring variables:

let age: number = 32;

Type inference

in many cases, TypeScript will know (infer) a type automatically (type annotation not needed):

let age = 32;

Primitive types

const age: number = 32;
const name: string = 'Alice';
const loggedIn: boolean = true;

Array types

const names: Array<string> = [];
names.push('Alice');

alternative syntax:

const names: string[] = [];
names.push('Alice');

Object types

type declaration:

let todo: {
  id: number;
  title: string;
  completed: boolean;
};

assignment:

todo = { id: 1, title: 'foo', completed: false };

Object types

optional entries are marked with ?

let todo: {
  id: number;
  title: string;
  completed: boolean;
  date?: string;
};

Combination

combining it all:

let todos: Array<{
  id: number;
  title: string;
  completed: boolean;
}>;
todos = [
  { id: 1, title: 'foo', completed: false },
  { id: 2, title: 'bar', completed: true },
];

Any

Sometimes we may want to make the type checker less strict

const nameInput: any = document.getElementById(
  'name-input'
);
console.log(nameInput.value);

Declaring a variable as any enables accessing arbitrary properties

Union types

variables that can be one of multiple types:

let width: string | number | undefined;

width = '16px';
width = 16;

Type aliases and interfaces

Type aliases and interfaces

Type aliases and interfaces: similar techniques that allow us to store a type declaration under a name

most commonly used for object structures, e.g.:

type Todo = {
  id: number;
  title: string;
  completed: boolean;
};

Type aliases and interfaces

type alias for objects:

type Todo = {
  id: number;
  title: string;
  completed: boolean;
};

interface for objects:

interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

Type aliases and interfaces

Type aliases can be somewhat more flexible and easy to use (comparison on StackOverflow)

Using type aliases / interfaces

const todos: Array<Todo> = [
  { id: 1, title: 'foo', completed: false },
  { id: 2, title: 'bar', completed: true },
];

Type aliases and interfaces

type aliases and interfaces should be capitalized (e.g. Todo, not todo)

Function signatures and function types

Function signatures

function shorten(text: string, maxLen: number): string {
  // ...
}
const shorten = (text: string, maxLen: number): string => {
  // ...
};

Function signatures

Functions without a return value: void

function logMessage(message: string): void {
  console.log(message);
}

Event handlers in React

example: event handlers in React:

import { MouseEvent } from 'react';
function handleClick(event: MouseEvent): void {
  event.stopPropagation();
  // ...
}
<button onClick={handleClick}>click</button>

Event handlers in React

common event types in React:

  • React.FormEvent (e.g. Submit)
  • React.ChangeEvent
  • React.MouseEvent (e.g. Click)

Function types

storing a function signature under a type alias:

// a validator is a function that receives a string
// and returns a boolean
type Validator = (s: string) => boolean;

applying the type alias:

const validateEmail: Validator = (s) => s.includes('@');

const validateYear: Validator = (s) =>
  new RegExp('^d{4}$').test(s);

Function types

when writing custom React components, we will pass in event handler functions as props:

type TodoListProps = {
  // properties
  todos: Array<Todo>;
  // event handlers
  onDelete: (id: number) => void;
  onChangeCompleted: (id: number, completed: boolean) => void;
}

Generics

Generics

Generics: type declarations that can receive more specific type information when applied (via <...>)

Generics

example: Array is a generic

const names: Array<string> = ['Alice', 'Bob', 'Charlie'];

Generics

example: React's useState can be used as a generic

const [todos, setTodos] = useState<Array<Todo>>([]);

Generics

example: React's event types can be used as generics:

function handleChange(
  event: ChangeEvent<HTMLInputElement>
) {
  const newValue = event.target.value;
  // ...
}

Type assertions

Type assertions

Type assertions enable treating an existing object as a specific type

this fails:

// type: HTMLElement or null
const nameInput = document.getElementById('name-input');
console.log(nameInput.value);

this works:

const nameInput = document.getElementById(
  'name-input'
) as HTMLInputElement;
console.log(nameInput.value);

Type assertions

type assertions can also work with any:

const nameInput = document.getElementById(
  'name-input'
) as any;
console.log(nameInput.value);

TypeScript: miscellaneous topics

Build

browsers only understand JavaScript, not TypeScript

during build: TypeScript is translated to JavaScript, all type information is discarded

Type declarations for libraries

some libraries include TypeScript declarations - e.g. redux.

other popular libraries mostly have type declaration packages that are prefixed with @types

e.g. for react: @types/react

Cheatsheets

React+TypeScript Cheatsheets: https://github.com/typescript-cheatsheets/react