TypeScript Cheatsheet
A comprehensive guide to TypeScript - JavaScript with static types for building robust and maintainable applications
Basic Types
Primitive Types
Core primitive types in TypeScript
// Boolean type
const isDone: boolean = false;
// Number type (integers and floats)
const decimal: number = 6;
const float: number = 6.5;
const hex: number = 0xf00d;
const binary: number = 0b1010;
// String type
const color: string = "blue";
const greeting: string = `Hello, ${name}`;
// Special Types
const notSure: any = 4; // Can be anything
const unknown: unknown = 4; // Type-safe any
const v: void = undefined; // absence of value
const n: null = null;
const u: undefined = undefined;
// Symbol (ES2015)
const sym: symbol = Symbol("key");
// BigInt (ES2020)
const bigInt: bigint = 100n;
Arrays and Tuples
Working with collections of values
// Arrays
const list: number[] = [1, 2, 3];
const altList: Array<number> = [1, 2, 3]; // Generic
// Read-only array
const readOnly: ReadonlyArray<number> = [1, 2, 3];
// Tuple - fixed length array with known types
const tuple: [string, number] = ["hello", 10];
tuple[0]; // string
tuple[1]; // number
// Tuple with optional element
const optTuple: [string, number?] = ["hello"];
// Named tuple elements (TS 4.0+)
const point: [x: number, y: number] = [10, 20];
console.log(`x: ${point[0]}, y: ${point[1]}`);
Object Types
Working with object structures
// Object type annotation
const user: { name: string; age: number } = {
name: "John",
age: 30
};
// Optional properties
const config: { debug?: boolean; mode: string } = {
mode: "production"
};
// Index signatures
const scores: { [key: string]: number } = {
math: 95,
science: 90
};
// Read-only properties
const point: { readonly x: number; readonly y: number } = {
x: 10,
y: 20
};
Interfaces & Types
Type Aliases
Create named types for reuse
// Type alias
type Point = {
x: number;
y: number;
};
// Using the type
const p: Point = { x: 10, y: 20 };
// Union types
type ID = number | string;
const id: ID = "abc123"; // or 123
// Literal types
type Direction = "up" | "down" | "left" | "right";
const move: Direction = "up";
// Combining types
type Employee = {
id: ID;
name: string;
};
// Extending types
type Person = { name: string };
type User = Person & { email: string };
// Function type
type Callback = (data: string) => void;
const fn: Callback = (data) => console.log(data);
Interfaces
Defining contracts for objects
// Basic interface
interface User {
name: string;
age: number;
}
// Optional properties
interface Config {
color?: string;
width: number;
}
// Read-only properties
interface Point {
readonly x: number;
readonly y: number;
}
// Method signatures
interface Calculator {
add(a: number, b: number): number;
subtract(a: number, b: number): number;
}
// Extending interfaces
interface Person {
name: string;
}
interface Employee extends Person {
department: string;
}
// Implementing interfaces
class Student implements Person {
name: string;
constructor(name: string) {
this.name = name;
}
}
Type vs Interface
Understanding when to use each
// Both can define object shapes
interface UserInterface {
name: string;
}
type UserType = {
name: string;
};
// Only interfaces can be merged (declaration merging)
interface API {
get(url: string): Promise<any>;
}
interface API {
post(url: string, data: any): Promise<any>;
}
// Only types can use advanced unions/intersections
type Status = "pending" | "fulfilled" | "rejected";
type Shape = Circle | Square;
type UserWithRole = User & { role: string };
// Interfaces for public APIs, Types for complex structures
// or when you need unions/intersections
Functions
Function Signatures
Typing functions and their parameters
// Basic function with types
function add(a: number, b: number): number {
return a + b;
}
// Arrow function
const multiply = (a: number, b: number): number => a * b;
// Optional parameters
function greet(name: string, greeting?: string): string {
return `${greeting || 'Hello'}, ${name}`;
}
// Default parameters
function createElement(tag: string, content: string = ''): string {
return `<${tag}>${content}</${tag}>`;
}
// Rest parameters
function sum(...numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0);
}
// Function overloads
function process(x: number): number;
function process(x: string): string;
function process(x: number | string): number | string {
if (typeof x === 'number') {
return x * 2;
} else {
return x.repeat(2);
}
}
Generics
Create reusable components with different types
// Generic function
function identity<T>(arg: T): T {
return arg;
}
// Calling with explicit type
const num = identity<number>(42);
// Letting TypeScript infer the type
const str = identity("hello");
// Generic interfaces
interface Box<T> {
value: T;
}
const numberBox: Box<number> = { value: 42 };
const stringBox: Box<string> = { value: "hello" };
// Generic constraints
interface Lengthwise {
length: number;
}
function getLength<T extends Lengthwise>(arg: T): number {
return arg.length;
}
// Now works with strings, arrays, but not numbers
getLength("hello"); // 5
getLength([1, 2, 3]); // 3
// getLength(42); // Error!
// Generic classes
class Queue<T> {
private data: T[] = [];
push(item: T): void {
this.data.push(item);
}
pop(): T | undefined {
return this.data.shift();
}
}
Advanced Types
Utility Types
Built-in type transformations
// Partial - makes all properties optional
interface User {
id: number;
name: string;
email: string;
}
function updateUser(user: User, updates: Partial<User>): User {
return { ...user, ...updates };
}
// Required - makes all properties required
type PartialConfig = { debug?: boolean; mode?: string };
const config: Required<PartialConfig> = {
debug: true,
mode: "test"
};
// Pick - create a type with a subset of properties
type UserBasics = Pick<User, 'id' | 'name'>;
// Omit - create a type without certain properties
type UserWithoutEmail = Omit<User, 'email'>;
// Record - create a dictionary with specific key and value types
const countries: Record<string, string> = {
US: "United States",
CA: "Canada",
MX: "Mexico"
};
// Exclude - remove types from a union
type Numbers = 1 | 2 | 3 | 4;
type EvenNumbers = Exclude<Numbers, 1 | 3>; // 2 | 4
// Extract - extract types from a union
type Colors = "red" | "green" | "blue" | "black" | "white";
type RGB = Extract<Colors, "red" | "green" | "blue">; // "red" | "green" | "blue"
// NonNullable - remove null and undefined
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>; // string
Type Guards
Narrow down types in conditionals
// typeof type guard
function process(value: string | number) {
if (typeof value === "string") {
// TypeScript knows value is a string here
return value.toUpperCase();
} else {
// TypeScript knows value is a number here
return value.toFixed(2);
}
}
// instanceof type guard
class Dog {
bark() { return "Woof!"; }
}
class Cat {
meow() { return "Meow!"; }
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
// TypeScript knows animal is Dog
return animal.bark();
} else {
// TypeScript knows animal is Cat
return animal.meow();
}
}
// in operator type guard
interface Fish { swim: () => void; }
interface Bird { fly: () => void; }
function move(animal: Fish | Bird) {
if ("swim" in animal) {
// TypeScript knows animal is Fish
return animal.swim();
} else {
// TypeScript knows animal is Bird
return animal.fly();
}
}
// User-defined type guards
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
function feed(pet: Fish | Bird) {
if (isFish(pet)) {
// TypeScript knows pet is Fish
pet.swim();
} else {
// TypeScript knows pet is Bird
pet.fly();
}
}
Mapped Types
Transform properties of existing types
// Read-only mapped type
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
interface User {
id: number;
name: string;
}
const readonlyUser: Readonly<User> = {
id: 1,
name: "John"
};
// Optional mapped type
type Optional<T> = {
[P in keyof T]?: T[P];
};
const optionalUser: Optional<User> = {
// All fields are optional now
name: "John"
};
// Mapping with modifiers
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
type Required<T> = {
[P in keyof T]-?: T[P];
};
// Remapping keys
type Getters<T> = {
[P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};
type UserGetters = Getters<User>;
// { getId: () => number, getName: () => string }
Conditional Types
Types that depend on type conditions
// Basic conditional type
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<123>; // false
// Extract return type of a function
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function fetchUser() { return { id: 1, name: "John" }; }
type User = ReturnType<typeof fetchUser>; // { id: number, name: string }
// Extract parameter types
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
function greet(name: string, age: number) { return `Hello, ${name}`; }
type GreetParams = Parameters<typeof greet>; // [string, number]
// Distributive conditional types
type ToArray<T> = T extends any ? T[] : never;
type StrNumArr = ToArray<string | number>; // string[] | number[]
// Non-distributive (use square brackets)
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
type Combined = ToArrayNonDist<string | number>; // (string | number)[]
Type Declarations
Declaration Files
Creating and using .d.ts files
// In types.d.ts
declare module "my-module" {
export function add(a: number, b: number): number;
export const version: string;
}
// Using the module
import { add, version } from "my-module";
// Global declarations (window.d.ts)
interface Window {
analytics: {
track(event: string, properties?: object): void;
identify(userId: string): void;
};
}
// Using globals
window.analytics.track("Page View");
// Augmenting existing modules
declare module "react" {
interface ComponentProps<T> {
testId?: string;
}
}
Type Assertions
Telling the compiler about types it can't infer
// "as" syntax (preferred)
const element = document.getElementById("root") as HTMLElement;
// Angle bracket syntax (not allowed in JSX)
const element2 = <HTMLElement>document.getElementById("root");
// Non-null assertion
function getLength(str: string | null) {
// "!" tells TypeScript that str is definitely not null
return str!.length;
}
// Const assertions
const colors = ["red", "green", "blue"] as const;
// Type is readonly ["red", "green", "blue"]
// Double assertion (use with caution)
const canvas = document.getElementById("canvas") as unknown as HTMLCanvasElement;
TypeScript & React
React Component Types
Common patterns for React components
// Functional component with typed props
interface GreetingProps {
name: string;
age?: number;
}
const Greeting: React.FC<GreetingProps> = ({ name, age }) => {
return <h1>Hello, {name}! {age && `You are ${age} years old.`}</h1>;
};
// Alternative function declaration (preferred in modern TS-React)
function Greeting({ name, age }: GreetingProps) {
return <h1>Hello, {name}! {age && `You are ${age} years old.`}</h1>;
}
// Props with children
interface LayoutProps {
title: string;
children: React.ReactNode;
}
const Layout = ({ title, children }: LayoutProps) => (
<div>
<h1>{title}</h1>
<main>{children}</main>
</div>
);
// Generic components
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
function List<T>({ items, renderItem }: ListProps<T>) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{renderItem(item)}</li>
))}
</ul>
);
}
Hooks with TypeScript
TypeScript patterns for React Hooks
// useState with type inference
const [user, setUser] = useState({ name: "John", age: 30 });
// useState with type annotation
const [user, setUser] = useState<User | null>(null);
// useRef with HTMLElement
const inputRef = useRef<HTMLInputElement>(null);
// useEffect with typed dependencies
useEffect(() => {
console.log(user.name);
}, [user]);
// useReducer with explicit types
interface State {
count: number;
}
type Action =
| { type: 'increment' }
| { type: 'decrement' }
| { type: 'reset'; payload: number };
function reducer(state: State, action: Action): State {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
case 'reset':
return { count: action.payload };
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });
// useContext with types
const ThemeContext = createContext<'light' | 'dark'>('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Child />
</ThemeContext.Provider>
);
}
function Child() {
const theme = useContext(ThemeContext);
return <div>Current theme: {theme}</div>;
}
Configuration & Tools
tsconfig.json
Common TypeScript configuration options
{
"compilerOptions": {
// Target ECMAScript version
"target": "es2020",
// Module system
"module": "esnext",
// Emit declaration files (.d.ts)
"declaration": true,
// Strict type checking
"strict": true,
// Error on unused variables
"noUnusedLocals": true,
// Error on unused parameters
"noUnusedParameters": true,
// Allow JavaScript files
"allowJs": true,
// Path aliases
"baseUrl": ".",
"paths": {
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"]
},
// React JSX handling
"jsx": "react",
// Interop with CommonJS modules
"esModuleInterop": true,
// Skip type checking node_modules
"skipLibCheck": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Migrating to TypeScript
Tips for migrating JavaScript to TypeScript
// 1. Start with allowJs and checkJs
// tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
// Other options...
}
}
// 2. Add // @ts-check to JavaScript files
// @ts-check
function add(a, b) {
return a + b;
}
// 3. Add JSDoc type annotations
/**
* @param {number} a First number
* @param {number} b Second number
* @returns {number} Sum of a and b
*/
function add(a, b) {
return a + b;
}
// 4. Convert files one by one to .ts
// 5. Enable strict mode gradually
// 6. Use type assertions for complex cases
const user = JSON.parse(data) as User;
// 7. Create declaration files for external libs
// for-external-lib.d.ts
declare module 'external-lib' {
export function doSomething(): void;
}
Type Definitions from npm
Working with DefinitelyTyped packages
// For libraries with built-in types:
// Just install the library
npm install react
// For libraries without types:
// Install @types package
npm install lodash
npm install @types/lodash
// Check if types are available:
// https://www.npmjs.com/~types
// Create your own types:
// mylib.d.ts
declare module 'mylib' {
export function helper(): void;
export const version: string;
}