TypeScript Cheat Sheet

Use this TypeScript cheat sheet as a quick reference for types, variables, functions, arrays, objects, interfaces, unions, generics, classes, modules, narrowing, utility types, and common patterns.

Basic TypeScript Syntax

TypeScript adds types to JavaScript. You can write normal JavaScript and add type annotations where they help.

const message: string = "Hello, TypeScript";

console.log(message);

Syntax Basics

  • Use : type after a variable, parameter, or return value.
  • TypeScript checks your code before it runs.
  • TypeScript compiles to JavaScript.
  • Use const for values that should not be reassigned.
  • Use let for values that need to change.
  • Avoid any unless you have a clear reason.

Run TypeScript

Install TypeScript

npm install -g typescript

Check the Version

tsc --version

Compile a File

tsc app.ts

This creates a JavaScript file:

app.js

Run the Compiled File

node app.js

Create a TypeScript Config File

tsc --init

This creates:

tsconfig.json

Basic Types

String

const name: string = "Alex";

Number

const age: number = 28;
const price: number = 19.99;

Boolean

const isLoggedIn: boolean = true;

Null

const selectedUser: null = null;

Undefined

let result: undefined = undefined;

Any

let value: any = "hello";

value = 42;
value = true;

any turns off type checking for that value. Use it sparingly.

Unknown

let value: unknown = "hello";

Use unknown when you do not know the type yet but still want type safety.

if (typeof value === "string") {
    console.log(value.toUpperCase());
}

Void

Use void for functions that do not return a value.

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

Never

Use never for functions that never finish normally.

function throwError(message: string): never {
    throw new Error(message);
}

Type Inference

TypeScript can often detect the type without an annotation.

const username = "Alex";
const score = 95;
const isActive = true;

TypeScript understands:

  • username is a string.
  • score is a number.
  • isActive is a boolean.

Add annotations when they make code clearer or when TypeScript cannot infer the type well.

let userId: string;

userId = "user-123";

Variables

const

const appName: string = "Mimo";

let

let count: number = 0;

count += 1;

Avoid var

var oldStyle = "Avoid this in new code";

Use const and let for modern TypeScript.

Arrays

Array of Strings

const languages: string[] = ["HTML", "CSS", "TypeScript"];

Alternative syntax:

const languages: Array<string> = ["HTML", "CSS", "TypeScript"];

Array of Numbers

const scores: number[] = [90, 85, 100];

Mixed Array with Union Types

const ids: Array<string | number> = ["user-1", 42, "user-2"];

Readonly Array

const roles: readonly string[] = ["admin", "editor"];

A readonly array prevents changes such as push().

roles.push("viewer");

This causes a TypeScript error.

Tuples

Tuples define an array with a fixed number of items and specific types.

const user: [string, number] = ["Alex", 28];

Access tuple values:

const name = user[0];
const age = user[1];

Named Tuple Elements

const point: [x: number, y: number] = [10, 20];

Optional Tuple Element

const response: [number, string?] = [200];

Use tuples for fixed pairs or small structured values. Use objects when field names matter more.

Objects

Object Type

const user: { name: string; age: number } = {
    name: "Alex",
    age: 28
};

Optional Property

const user: { name: string; email?: string } = {
    name: "Alex"
};

The ? means the property may be missing.

Readonly Property

const user: { readonly id: number; name: string } = {
    id: 1,
    name: "Alex"
};

This prevents reassignment:

user.id = 2;

TypeScript reports an error.

Type Aliases

Use type to name a type.

type User = {
    id: number;
    name: string;
    email?: string;
};

const user: User = {
    id: 1,
    name: "Alex"
};

Type aliases make object shapes easier to reuse.

Alias for a Union

type Status = "draft" | "published" | "archived";

const status: Status = "published";

Alias for an ID

type UserId = string | number;

const id: UserId = "user-123";

Interfaces

Use interface to describe object shapes.

interface User {
    id: number;
    name: string;
    email?: string;
}

const user: User = {
    id: 1,
    name: "Alex"
};

Extend an Interface

interface Person {
    name: string;
}

interface Developer extends Person {
    language: string;
}

const developer: Developer = {
    name: "Sam",
    language: "TypeScript"
};

Interface with Method

interface User {
    name: string;
    greet(): string;
}

const user: User = {
    name: "Alex",
    greet() {
        return `Hello, ${this.name}`;
    }
};

Type Alias vs Interface

Use either for object shapes in most beginner and intermediate code.

Use interface when:

  • You describe object shapes.
  • You want to extend another object type.
  • You work with classes or public APIs.

Use type when:

  • You need unions.
  • You need tuples.
  • You need utility types or mapped types.
  • You want a short alias for a complex type.

Example union:

type Theme = "light" | "dark";

Example interface:

interface ButtonProps {
    label: string;
    disabled?: boolean;
}

Union Types

A union allows more than one type.

let id: string | number;

id = "user-123";
id = 123;

Union with Literal Values

type Size = "small" | "medium" | "large";

const buttonSize: Size = "medium";

This prevents invalid values.

const buttonSize: Size = "extra-large";

TypeScript reports an error.

Intersection Types

An intersection combines multiple types.

type Person = {
    name: string;
};

type Employee = {
    employeeId: number;
};

type TeamMember = Person & Employee;

const member: TeamMember = {
    name: "Alex",
    employeeId: 123
};

Use intersections when a value must match multiple type shapes.

Literal Types

Literal types restrict values to exact strings, numbers, or booleans.

type Direction = "up" | "down" | "left" | "right";

function move(direction: Direction) {
    console.log(`Moving ${direction}`);
}

move("up");

Invalid value:

move("forward");

TypeScript reports an error.

Functions

Function Parameters

function greet(name: string) {
    return `Hello, ${name}`;
}

Return Type

function add(a: number, b: number): number {
    return a + b;
}

Void Return

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

Optional Parameter

function greet(name?: string): string {
    return `Hello, ${name ?? "Guest"}`;
}

Default Parameter

function greet(name: string = "Guest"): string {
    return `Hello, ${name}`;
}

Function Type

type MathOperation = (a: number, b: number) => number;

const add: MathOperation = (a, b) => a + b;

Arrow Functions

const greet = (name: string): string => {
    return `Hello, ${name}`;
};

Short version:

const double = (number: number): number => number * 2;

Use return types for exported functions, shared helpers, and code where clarity matters.

Objects as Function Parameters

type User = {
    name: string;
    age: number;
};

function printUser(user: User): void {
    console.log(`${user.name} is ${user.age}`);
}

Call the function:

printUser({
    name: "Alex",
    age: 28
});

Destructured Parameter

function printUser({ name, age }: User): void {
    console.log(`${name} is ${age}`);
}

Optional Chaining

Use optional chaining to safely access nested properties.

type User = {
    profile?: {
        email?: string;
    };
};

const user: User = {};

console.log(user.profile?.email);

If profile is missing, the result is undefined instead of an error.

Nullish Coalescing

Use ?? to provide a fallback for null or undefined.

const username = user.profile?.email ?? "No email";

Unlike ||, nullish coalescing does not replace valid values like 0 or an empty string.

const count = 0;

const result = count ?? 10;

console.log(result);

This prints 0.

Type Narrowing

Type narrowing helps TypeScript understand a more specific type.

typeof

function printId(id: string | number): void {
    if (typeof id === "string") {
        console.log(id.toUpperCase());
    } else {
        console.log(id.toFixed(0));
    }
}

in

type Admin = {
    role: "admin";
    permissions: string[];
};

type Member = {
    role: "member";
    plan: string;
};

function showUser(user: Admin | Member): void {
    if ("permissions" in user) {
        console.log(user.permissions);
    } else {
        console.log(user.plan);
    }
}

instanceof

function printDate(value: Date | string): void {
    if (value instanceof Date) {
        console.log(value.toISOString());
    } else {
        console.log(value.toUpperCase());
    }
}

Discriminated Unions

A discriminated union uses a shared property to identify each shape.

type LoadingState = {
    status: "loading";
};

type SuccessState = {
    status: "success";
    data: string[];
};

type ErrorState = {
    status: "error";
    message: string;
};

type State = LoadingState | SuccessState | ErrorState;

Use the shared property to narrow the type.

function renderState(state: State): string {
    if (state.status === "loading") {
        return "Loading...";
    }

    if (state.status === "success") {
        return state.data.join(", ");
    }

    return state.message;
}

This pattern works well for loading states, form states, and API responses.

Generics

Generics let a type stay flexible while still preserving type safety.

function identity<T>(value: T): T {
    return value;
}

const text = identity<string>("hello");
const number = identity<number>(42);

TypeScript can often infer the generic type:

const text = identity("hello");

Generic Array Helper

function getFirst<T>(items: T[]): T | undefined {
    return items[0];
}

const firstName = getFirst(["Alex", "Sam"]);
const firstScore = getFirst([90, 85]);

Generic Object Constraint

function getId<T extends { id: number }>(item: T): number {
    return item.id;
}

const userId = getId({
    id: 1,
    name: "Alex"
});

Use constraints when the generic value must have certain properties.

Enums

Enums define named values.

enum Role {
    Admin,
    Editor,
    Viewer
}

const userRole = Role.Admin;

String enums are clearer in logs and API values.

enum Status {
    Draft = "draft",
    Published = "published",
    Archived = "archived"
}

const status = Status.Published;

Many TypeScript projects prefer union types for simple fixed values:

type Status = "draft" | "published" | "archived";

Classes

Basic Class

class User {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    greet(): string {
        return `Hello, ${this.name}`;
    }
}

const user = new User("Alex");

console.log(user.greet());

Public, Private, and Protected

class Account {
    public email: string;
    private password: string;

    constructor(email: string, password: string) {
        this.email = email;
        this.password = password;
    }
}

Parameter Properties

class User {
    constructor(public name: string, private age: number) {}

    greet(): string {
        return `Hello, ${this.name}`;
    }
}

Parameter properties reduce repeated code in classes.

Inheritance

class Animal {
    constructor(public name: string) {}

    speak(): string {
        return "Sound";
    }
}

class Dog extends Animal {
    speak(): string {
        return "Bark";
    }
}

Access Modifiers

public

Available anywhere.

class User {
    public name: string = "Alex";
}

private

Available only inside the class.

class User {
    private password: string = "secret";
}

protected

Available inside the class and subclasses.

class User {
    protected id: number = 1;
}

readonly

Can be set once, then not changed.

class User {
    readonly id: number;

    constructor(id: number) {
        this.id = id;
    }
}

Modules

Export a Function

export function add(a: number, b: number): number {
    return a + b;
}

Import a Function

import { add } from "./math";

console.log(add(2, 3));

Default Export

export default function greet(name: string): string {
    return `Hello, ${name}`;
}

Default Import

import greet from "./greet";

console.log(greet("Alex"));

Export a Type

export type User = {
    id: number;
    name: string;
};

Import a Type

import type { User } from "./types";

Use import type when you only need the type, not a runtime value.

Utility Types

TypeScript includes utility types that transform existing types.

Partial<T>

Makes all properties optional.

type User = {
    name: string;
    email: string;
};

const updates: Partial<User> = {
    email: "alex@example.com"
};

Required<T>

Makes all properties required.

type User = {
    name?: string;
    email?: string;
};

const user: Required<User> = {
    name: "Alex",
    email: "alex@example.com"
};

Readonly<T>

Makes all properties readonly.

type User = {
    name: string;
};

const user: Readonly<User> = {
    name: "Alex"
};

Pick<T, Keys>

Creates a type with selected properties.

type User = {
    id: number;
    name: string;
    email: string;
};

type UserPreview = Pick<User, "id" | "name">;

Omit<T, Keys>

Creates a type without selected properties.

type User = {
    id: number;
    name: string;
    password: string;
};

type PublicUser = Omit<User, "password">;

Record<Keys, Type>

Creates an object type with known keys and value types.

type Role = "admin" | "editor" | "viewer";

const permissions: Record<Role, string[]> = {
    admin: ["create", "edit", "delete"],
    editor: ["edit"],
    viewer: ["read"]
};

Type Assertions

Type assertions tell TypeScript to treat a value as a specific type.

const input = document.querySelector("input") as HTMLInputElement;

console.log(input.value);

Use assertions only when you know more than TypeScript can infer.

Safer DOM Check

const input = document.querySelector("input");

if (input instanceof HTMLInputElement) {
    console.log(input.value);
}

This checks the value at runtime before using it.

DOM Types

TypeScript knows many browser element types.

Button

const button = document.querySelector("button");

if (button instanceof HTMLButtonElement) {
    button.disabled = true;
}

Input

const input = document.querySelector("#email");

if (input instanceof HTMLInputElement) {
    console.log(input.value);
}

Form

const form = document.querySelector("form");

if (form instanceof HTMLFormElement) {
    form.addEventListener("submit", (event) => {
        event.preventDefault();
    });
}

Event Types

Click Event

const button = document.querySelector("button");

button?.addEventListener("click", (event) => {
    console.log(event.type);
});

Input Event

const input = document.querySelector("#email");

input?.addEventListener("input", (event) => {
    const target = event.target;

    if (target instanceof HTMLInputElement) {
        console.log(target.value);
    }
});

Submit Event

const form = document.querySelector("form");

form?.addEventListener("submit", (event) => {
    event.preventDefault();
    console.log("Form submitted");
});

Async TypeScript

Typed Async Function

async function getUser(): Promise<string> {
    return "Alex";
}

Fetch with a Type

type User = {
    id: number;
    name: string;
    email: string;
};

async function fetchUser(id: number): Promise<User> {
    const response = await fetch(`/api/users/${id}`);

    if (!response.ok) {
        throw new Error("Failed to fetch user");
    }

    const user = await response.json();

    return user;
}

API Response Type

type ApiResponse<T> = {
    data: T;
    error?: string;
};

type User = {
    id: number;
    name: string;
};

const response: ApiResponse<User> = {
    data: {
        id: 1,
        name: "Alex"
    }
};

Generic response types help keep API code reusable.

Common TypeScript Patterns

Loading State

type LoadingState =
    | { status: "idle" }
    | { status: "loading" }
    | { status: "success"; data: string[] }
    | { status: "error"; message: string };

function getMessage(state: LoadingState): string {
    switch (state.status) {
        case "idle":
            return "Ready";
        case "loading":
            return "Loading";
        case "success":
            return `${state.data.length} items loaded`;
        case "error":
            return state.message;
    }
}

Form Values

type LoginForm = {
    email: string;
    password: string;
    rememberMe: boolean;
};

const formValues: LoginForm = {
    email: "alex@example.com",
    password: "secret",
    rememberMe: true
};

Component Props

type ButtonProps = {
    label: string;
    disabled?: boolean;
    onClick: () => void;
};

function createButton(props: ButtonProps): HTMLButtonElement {
    const button = document.createElement("button");

    button.textContent = props.label;
    button.disabled = props.disabled ?? false;
    button.addEventListener("click", props.onClick);

    return button;
}

Dictionary Object

type User = {
    id: number;
    name: string;
};

const usersById: Record<number, User> = {
    1: { id: 1, name: "Alex" },
    2: { id: 2, name: "Sam" }
};

Safe Unknown Parsing

function isUser(value: unknown): value is { name: string } {
    return (
        typeof value === "object" &&
        value !== null &&
        "name" in value &&
        typeof value.name === "string"
    );
}

const data: unknown = JSON.parse('{"name":"Alex"}');

if (isUser(data)) {
    console.log(data.name);
}

This pattern helps when working with external data.

Common Mistakes

Using any Too Often

let user: any = {
    name: "Alex"
};

console.log(user.email.toUpperCase());

This can fail at runtime because TypeScript cannot protect you.

Better:

type User = {
    name: string;
    email?: string;
};

const user: User = {
    name: "Alex"
};

if (user.email) {
    console.log(user.email.toUpperCase());
}

Forgetting Optional Properties

type User = {
    name: string;
    email?: string;
};

function printEmail(user: User): void {
    console.log(user.email.toUpperCase());
}

Better:

function printEmail(user: User): void {
    if (user.email) {
        console.log(user.email.toUpperCase());
    }
}

Optional properties can be undefined.

Confusing type and Runtime Values

type User = {
    name: string;
};

console.log(User);

This does not work because types do not exist at runtime.

Better:

type User = {
    name: string;
};

const user: User = {
    name: "Alex"
};

console.log(user);

Overusing Type Assertions

const input = document.querySelector("#email") as HTMLInputElement;

console.log(input.value);

This can fail if the element does not exist or is not an input.

Better:

const input = document.querySelector("#email");

if (input instanceof HTMLInputElement) {
    console.log(input.value);
}

Passing the Wrong Literal Value

type Theme = "light" | "dark";

const theme: Theme = "blue";

Better:

const theme: Theme = "dark";

Literal unions only allow the values you define.

Debugging Tips

Read the Type Error Carefully

TypeScript errors usually tell you:

  • Which value has the wrong type
  • Which type TypeScript expected
  • Which type you provided
  • Where the mismatch happened

Hover Types in Your Editor

Most editors can show inferred types when you hover over a variable.

const names = ["Alex", "Sam"];

Hovering over names should show string[].

Add Types to Function Boundaries

function calculateTotal(prices: number[]): number {
    return prices.reduce((sum, price) => sum + price, 0);
}

Typing function parameters and return values makes errors easier to find.

Prefer unknown Over any

function handleValue(value: unknown): void {
    if (typeof value === "string") {
        console.log(value.toUpperCase());
    }
}

unknown forces you to check the value before using it.

Check the Compiled JavaScript

If something works in TypeScript but fails in the browser or Node, check the JavaScript output.

tsc app.ts

Then inspect:

app.js

Quick Reference

Create a String

const name: string = "Alex";

Create a Number

const age: number = 28;

Create a Boolean

const isActive: boolean = true;

Create an Array

const items: string[] = ["one", "two"];

Create an Object Type

type User = {
    id: number;
    name: string;
};

Create an Interface

interface User {
    id: number;
    name: string;
}

Create a Union

type Status = "draft" | "published";

Type a Function

function add(a: number, b: number): number {
    return a + b;
}

Create a Generic Function

function getFirst<T>(items: T[]): T | undefined {
    return items[0];
}

Use Optional Chaining

const email = user.profile?.email;

Use Nullish Coalescing

const displayName = name ?? "Guest";

Use a Utility Type

type UserUpdate = Partial<User>;

Import a Type

import type { User } from "./types";

Compile TypeScript

tsc app.ts