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.
Learn TypeScript on Mimo
const message: string = "Hello, TypeScript";
console.log(message);
Syntax Basics
- Use
: typeafter a variable, parameter, or return value. - TypeScript checks your code before it runs.
- TypeScript compiles to JavaScript.
- Use
constfor values that should not be reassigned. - Use
letfor values that need to change. - Avoid
anyunless you have a clear reason.
Run TypeScript
Install TypeScript
Bash
npm install -g typescript
Check the Version
Bash
tsc --version
Compile a File
Bash
tsc app.ts
This creates a JavaScript file:
Bash
app.js
Run the Compiled File
Bash
node app.js
Create a TypeScript Config File
Bash
tsc --init
This creates:
Bash
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:
usernameis a string.scoreis a number.isActiveis 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.
Bash
tsc app.ts
Then inspect:
Bash
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
Bash
tsc app.ts
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot