Cheat sheet · TypeScript
TypeScript Cheat Sheet
A scannable TypeScript reference covering basic types, interfaces and type aliases, arrays and tuples, functions, union and literal types, generics, enums, type narrowing, and the built-in utility types.
A cheat sheet is for the thing you have understood once and cannot quite remember the shape of. It is written to be scanned, so the common cases come first. Starting from nothing? The TypeScript exercises are the right first step; come back here once the syntax is something you are recalling rather than meeting. Looking for another language? See every cheat sheet.
This page is a fast-scanning reference for TypeScript syntax you'll reach for constantly - not a
tutorial. Each section is a self-contained group of snippets, so jump straight to the part you need.
Where a line's real, printed output isn't obvious from reading it, a comment after it (or a text block
underneath) shows exactly what the compiler or the running program produces.
Basic Types
let name: string = "Priya"; // annotated
let age = 27; // inferred as number
let gpa = 3.85; // inferred as number
let isActive = true; // inferred as boolean
typeof age; // "number"Converting between types is done with Number(), String(), Boolean(), and the older parseInt() /
parseFloat(). parseInt() stops at the first character that isn't part of a whole number, rather than
rejecting the text outright:
Number("42"); // 42
String(17); // "17"
Boolean(0); // false
parseInt("3.9", 10); // 3 — parses only the integer part
parseFloat("2.5"); // 2.5Type Annotations vs Inference
A variable declared with an initial value doesn't need an annotation - TypeScript infers the type from the value and enforces it exactly as strictly as a written one:
let elevation = 1795; // inferred as number, same protection as writing `: number` yourself
let total: number; // no initializer here, so the annotation is what fixes the type
total = 10 + 25;let age: number = 30;
let label: string = "thirty";
age = label;main.ts(3,1): error TS2322: Type 'string' is not assignable to type 'number'.Interfaces & Type Aliases
interface Point {
x: number;
y: number;
}
type Coordinate = {
x: number;
y: number;
};
const a: Point = { x: 1, y: 2 };
const b: Coordinate = a; // same shape as Point, so this is allowed — structural typing? marks a property optional; readonly blocks reassignment after the object is created:
interface Product {
name: string;
price: number;
readonly sku: string;
discount?: number;
}A type alias can also combine shapes with | (union) and & (intersection), which interface can't
do directly:
type Id = string | number; // union
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged; // intersection — has both name and age
const p: Person = { name: "Kai", age: 40 };Arrays & Tuples
Type[] and Array<Type> mean the same thing. A tuple, [Type1, Type2], is different: it has a fixed
length, and each position keeps its own type.
const scores: number[] = [92, 88, 79];
const names: Array<string> = ["Ana", "Ben"];
scores.push(100); // ok
names.push("Chi"); // ok
const point: [number, number] = [3, 4];
const [x, y] = point; // destructuring — x = 3, y = 4
point[0] = 10; // ok — a tuple isn't automatically read-onlyFunctions
function add(a: number, b: number): number {
return a + b;
}
const multiply = (a: number, b: number): number => a * b; // arrow function
function greet(name: string, greeting = "Hello"): string { // default parameter
return `${greeting}, ${name}!`;
}
function shout(text: string, volume?: number): string { // optional parameter — type is number | undefined
return volume !== undefined && volume > 5 ? text.toUpperCase() : text;
}
add(2, 3); // 5
multiply(2, 3); // 6
greet("Mei"); // "Hello, Mei!"
greet("Mei", "Hey"); // "Hey, Mei!"
shout("careful", 8); // "CAREFUL"Every parameter needs a type - either written directly or, for an optional or default parameter, inferred from its default value. There's no fallback to "anything goes" the way an untyped JavaScript parameter works.
Union & Literal Types
let id: string | number = "A1";
id = 42; // ok — still matches the unionA literal type is a type with exactly one legal value; a union of literal types describes a fixed set of options, and anything outside that set is rejected at compile time - even a value of the right general type:
type Direction = "up" | "down" | "left" | "right";
let move: Direction = "up";
move = "sideways";main.ts(3,1): error TS2322: Type '"sideways"' is not assignable to type 'Direction'.Generics
A generic type parameter, <T>, is a placeholder for "whatever type this call is using" - inferred
fresh per call, and checked exactly like a concrete type would be:
function identity<T>(value: T): T {
return value;
}
identity<string>("hello"); // "hello", T given explicitly
identity(42); // 42, T inferred as number
function firstElement<T>(items: T[]): T {
return items[0];
}
firstElement([10, 20, 30]); // 10
function pair<A, B>(first: A, second: B): [A, B] {
return [first, second];
}
console.log(pair("age", 30));[ 'age', 30 ]<T extends ...> constrains what a generic type parameter must have, without pinning it to one concrete
type:
function longest<T extends { length: number }>(a: T, b: T): T {
return a.length >= b.length ? a : b;
}
longest("hello", "hi"); // "hello"Enums
enum Compass {
Up,
Down,
Left,
Right,
}
Compass.Up; // 0
Compass.Right; // 3
enum Status {
Active = "ACTIVE",
Inactive = "INACTIVE",
}
Status.Active; // "ACTIVE"An enum-typed variable only accepts the enum's own members - not even the exact matching underlying
string is assignable directly. as const locks an object or array literal down to its most specific,
read-only type:
const config = { mode: "fast", retries: 3 } as const; // every property becomes readonly and literal-typed
config.mode = "slow";main.ts(3,8): error TS2540: Cannot assign to 'mode' because it is a read-only property.Type Narrowing
function describe(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(1);
}
describe("hi"); // "HI"
describe(3); // "3.0"A function whose return type is written value is Type (instead of a plain boolean) narrows the
argument's type for whoever calls it - this is a custom type guard:
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every((item) => typeof item === "string");
}
function shoutAll(value: unknown): string[] {
return isStringArray(value) ? value.map((s) => s.toUpperCase()) : [];
}
console.log(shoutAll(["a", "b"]));
console.log(shoutAll(42));[ 'A', 'B' ]
[]Utility Types
These build a new type out of an existing one. They exist purely for the compiler - there's no value
attached to any of them, so there's nothing to console.log and no runtime output to show, only a
description of the shape each one produces.
interface User {
id: number;
name: string;
email: string;
}
type UserDraft = Partial<User>; // every property becomes optional: { id?: number; name?: string; email?: string }
type UserPreview = Pick<User, "id" | "name">; // only the listed properties: { id: number; name: string }
type PublicUser = Omit<User, "email">; // every property except the listed ones: { id: number; name: string }
type Scoreboard = Record<string, number>; // an object type with string keys and number valuesPartial is the type you reach for when updating an object one field at a time; Pick and Omit are
mirror images of each other for narrowing an interface down to a subset of its own properties; Record
builds a dictionary-shaped type from a key type and a value type.
Try any snippet with your own values in the TypeScript playground.