majority of React projects will use TypeScript instead of JavaScript
static typing → better autocompletion and error detection
topics:
data types may be specified explicitly by the developer or inferred by the development invironment
benefits:
example:
let names: Array<string> = [];
names.push('Alice');
names.push('Bob');
console.log(names[0].toUpperCase());
experiment with TypeScript online:
data types that we'll use:
variable types can be specified when declaring variables:
let age: number = 32;
in many cases, TypeScript will know (infer) a type automatically (type annotation not needed):
let age = 32;
const age: number = 32;
const name: string = 'Alice';
const loggedIn: boolean = true;
const names: Array<string> = [];
names.push('Alice');
alternative syntax:
const names: string[] = [];
names.push('Alice');
type declaration:
let todo: {
id: number;
title: string;
completed: boolean;
};
assignment:
todo = { id: 1, title: 'foo', completed: false };
optional entries are marked with ?
let todo: {
id: number;
title: string;
completed: boolean;
date?: string;
};
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 },
];
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
variables that can be one of multiple types:
let width: string | number | undefined;
width = '16px';
width = 16;
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 alias for objects:
type Todo = {
id: number;
title: string;
completed: boolean;
};
interface for objects:
interface Todo {
id: number;
title: string;
completed: boolean;
}
Type aliases can be somewhat more flexible and easy to use (comparison on StackOverflow)
const todos: Array<Todo> = [
{ id: 1, title: 'foo', completed: false },
{ id: 2, title: 'bar', completed: true },
];
type aliases and interfaces should be capitalized (e.g. Todo
, not todo
)
function shorten(text: string, maxLen: number): string {
// ...
}
const shorten = (text: string, maxLen: number): string => {
// ...
};
Functions without a return value: void
function logMessage(message: string): void {
console.log(message);
}
example: event handlers in React:
import { MouseEvent } from 'react';
function handleClick(event: MouseEvent): void {
event.stopPropagation();
// ...
}
<button onClick={handleClick}>click</button>
common event types in React:
React.FormEvent
(e.g. Submit)React.ChangeEvent
React.MouseEvent
(e.g. Click)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);
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: type declarations that can receive more specific type information when applied (via <...>
)
example: Array
is a generic
const names: Array<string> = ['Alice', 'Bob', 'Charlie'];
example: React's useState
can be used as a generic
const [todos, setTodos] = useState<Array<Todo>>([]);
example: React's event types can be used as generics:
function handleChange(
event: ChangeEvent<HTMLInputElement>
) {
const newValue = event.target.value;
// ...
}
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 can also work with any
:
const nameInput = document.getElementById(
'name-input'
) as any;
console.log(nameInput.value);
browsers only understand JavaScript, not TypeScript
during build: TypeScript is translated to JavaScript, all type information is discarded
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
React+TypeScript Cheatsheets: https://github.com/typescript-cheatsheets/react