TypeScript: popular alternative to JavaScript
supports static typing → better autocompletion and error detection
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 and declarations 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;
};
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
Type aliases can be somewhat more flexible and easy to use (comparison on StackOverflow)
type alias for objects:
type Todo = {
id: number;
title: string;
completed: boolean;
};
interface for objects:
interface Todo {
id: number;
title: string;
completed: boolean;
}
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);
}
storing a function signature under a type alias:
type Validator = (s: string) => boolean;
applying the type alias:
const validateEmail: Validator = (s) => s.includes('@');
const validateYear: Validator = (s) => {
return new RegExp('^d{4}$').test(s);
};
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);
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 [name, setName] = useState<string>('');
example: React's event types can be used as generics:
function handleChange(
event: ChangeEvent<HTMLInputElement>
) {
const newValue = event.target.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