TypeScript 107 🔷 Cheatsheet
This cheatsheet is a dense, practical reference for TypeScript’s type system, syntax, and compiler configuration. It prioritizes the features that appear most frequently in daily development—type annotations, generics, utility types, narrowing, and the tsconfig.json settings that determine how strict the compiler is. It reflects TypeScript 5.x, where satisfies, const type parameters, and decorators (standardized) are stable.
Key point: TypeScript is JavaScript plus a static type system that erases at compile time. Types do not exist at runtime; they are checked by the compiler and stripped from the output. Every type annotation is a compile-time constraint, not a runtime guarantee. The tsconfig.json strict flag is the difference between a type system that catches bugs and one that merely documents intent.
Compiler Commands
| Command | Purpose |
|---|---|
tsc | Compile according to tsconfig.json |
tsc file.ts | Compile a single file |
tsc --init | Generate a default tsconfig.json |
tsc --noEmit | Type-check only, no output |
tsc --watch | Watch mode, recompile on change |
tsc --build | Build project references |
tsc --declaration | Emit .d.ts files |
tsc --strict | Enable all strict checks |
tsc --version | Print compiler version |
npx tsc | Run from a local install |
Primitive Types
| Type | Example | Notes |
|---|---|---|
string | 'hello' | |
number | 42, 3.14 | No separate int/float |
boolean | true, false | |
bigint | 42n | Requires target: ES2020+ |
symbol | Symbol('id') | |
null | null | Only with strictNullChecks |
undefined | undefined | |
void | undefined (function return) | |
never | unreachable | Function that throws or loops forever |
unknown | any value, requires narrowing | Safe any |
any | any value, no checks | Escape hatch |
Type Annotations
// Variables
let name: string = 'Rohit';
const age: number = 30;
// Functions
function greet(name: string): string {
return `Hello, ${name}`;
}
// Arrow functions
const add = (a: number, b: number): number => a + b;
// Optional and default parameters
function log(msg: string, level?: string, prefix = 'LOG'): void {
// level: string | undefined
}
// Rest parameters
function sum(...nums: number[]): number {
return nums.reduce((a, b) => a + b, 0);
}
// Return type inference (usually omit)
const double = (n: number) => n * 2; // inferred number
// Explicit return type for public APIs (recommended)
export function parse(input: string): Result { ... }
Object and Array Types
// Object type
let user: { name: string; age: number };
user = { name: 'Rohit', age: 30 };
// Optional properties
let config: { host: string; port?: number };
// Readonly properties
let point: { readonly x: number; readonly y: number };
point = { x: 0, y: 0 };
// point.x = 1; // Error
// Index signature
let scores: { [key: string]: number };
scores = { alice: 10, bob: 20 };
// Arrays
let nums: number[] = [1, 2, 3];
let strs: Array<string> = ['a', 'b'];
let matrix: number[][] = [[1, 2], [3, 4]];
// Tuples
let pair: [string, number] = ['age', 30];
let triple: [string, number, boolean] = ['id', 1, true];
// Named tuples
let point3d: [x: number, y: number, z: number] = [0, 0, 0];
// Optional tuple elements
let range: [number, number?] = [1];
// Readonly tuple
let immutable: readonly [number, number] = [0, 0];
// Readonly array
let ro: readonly number[] = [1, 2, 3];
Union and Intersection Types
// Union: one of several types
let id: string | number;
id = 'abc'; // OK
id = 42; // OK
// Intersection: all types combined
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged;
const p: Person = { name: 'Rohit', age: 30 };
// Literal types
type Direction = 'north' | 'south' | 'east' | 'west';
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
// Template literal types
type Event = `on${Capitalize<string>}`;
type Route = `/users/${string}`;
// Discriminated union
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number }
| { kind: 'rect'; width: number; height: number };
function area(s: Shape): number {
switch (s.kind) {
case 'circle': return Math.PI * s.radius ** 2;
case 'square': return s.side ** 2;
case 'rect': return s.width * s.height;
}
}
Interfaces vs Type Aliases
// Interface: extendable, mergeable
interface User {
name: string;
age: number;
}
interface User {
email: string; // Merges into the same User
}
interface Admin extends User {
role: 'admin';
}
// Type alias: can alias any type, not just objects
type ID = string | number;
type Callback = (err: Error | null, data?: string) => void;
type UserRecord = Record<string, User>;
When to use: Interfaces for public object shapes that may be extended; type aliases for unions, tuples, mapped types, and primitives. Interfaces can be declaration-merged; type aliases cannot.
Functions and Overloads
// Function type
type Handler = (event: Event) => void;
// Call signatures in interface
interface Logger {
(msg: string): void;
level: string;
}
// Overloads
function greet(name: string): string;
function greet(name: string[]): string[];
function greet(name: string | string[]): string | string[] {
return Array.isArray(name) ? name.map(n => `Hi ${n}`) : `Hi ${name}`;
}
// This types
function handler(this: HTMLElement, event: Event): void {
this.classList.add('active');
}
// Generic function
function identity<T>(x: T): T { return x; }
// Constraint
function first<T extends { id: number }>(items: T[]): T | undefined {
return items[0];
}
// Default type parameter
function wrap<T = string>(x?: T): T[] { return x ? [x] : []; }
Generics
// Generic interface
interface Box<T> {
value: T;
}
// Generic class
class Stack<T> {
private items: T[] = [];
push(item: T): void { this.items.push(item); }
pop(): T | undefined { return this.items.pop(); }
get size(): number { return this.items.length; }
}
// Multiple type parameters
function pair<A, B>(a: A, b: B): [A, B] { return [a, b]; }
// Constraints
function pluck<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
// Const type parameters (TS 5.0)
function tuple<const T extends readonly unknown[]>(...args: T): T {
return args;
}
const t = tuple('a', 'b'); // readonly ['a', 'b']
// Conditional types
type IsString<T> = T extends string ? true : false;
// Mapped types
type Optional<T> = { [K in keyof T]?: T[K] };
type ReadonlyDeep<T> = {
readonly [K in keyof T]: T[K] extends object ? ReadonlyDeep<T[K]> : T[K];
};
Utility Types
| Utility | Purpose | Example |
|---|---|---|
Partial<T> | All properties optional | Partial<User> |
Required<T> | All properties required | Required<Partial<User>> |
Readonly<T> | All properties readonly | Readonly<User> |
Record<K, V> | Object with keys K, values V | Record<string, number> |
Pick<T, K> | Select subset of properties | Pick<User, 'name' | 'email'> |
Omit<T, K> | Remove properties | Omit<User, 'password'> |
Exclude<T, U> | Remove U from T | Exclude<'a' | 'b', 'a'> |
Extract<T, U> | Keep only U in T | Extract<'a' | 'b', 'a'> |
NonNullable<T> | Remove null/undefined | NonNullable<string | null> |
ReturnType<F> | Return type of function | ReturnType<typeof fn> |
Parameters<F> | Parameters tuple | Parameters<typeof fn> |
Awaited<T> | Unwrap Promise | Awaited<Promise<string>> |
InstanceType<C> | Instance of class | InstanceType<typeof Date> |
Type Narrowing
// typeof
function format(value: string | number): string {
if (typeof value === 'string') {
return value.toUpperCase();
}
return value.toFixed(2);
}
// instanceof
function isDate(value: Date | string): boolean {
return value instanceof Date;
}
// in
type Bird = { fly: () => void };
type Fish = { swim: () => void };
function move(animal: Bird | Fish) {
if ('fly' in animal) animal.fly();
else animal.swim();
}
// Discriminated unions (most reliable)
type Result =
| { ok: true; value: number }
| { ok: false; error: string };
function handle(r: Result) {
if (r.ok) return r.value;
return r.error;
}
// User-defined type guard
function isString(x: unknown): x is string {
return typeof x === 'string';
}
// Assertion function
function assertString(x: unknown): asserts x is string {
if (typeof x !== 'string') throw new Error('Not a string');
}
satisfies (TS 4.9)
// `satisfies` checks conformance without widening
const config = {
port: 8080,
host: 'localhost',
} satisfies { port: number; host: string };
config.port.toFixed(); // OK; type is number, not number | string
// Preserves literal types
const palette = {
primary: '#0070f3',
secondary: '#ff0080',
} satisfies Record<string, string>;
palette.primary.toUpperCase(); // OK; still string
// vs `as const` + satisfies
const routes = {
home: '/',
users: '/users',
} as const satisfies Record<string, string>;
type Route = typeof routes[keyof typeof routes]; // '/' | '/users'
Classes
class Animal {
// Parameter properties (shorthand)
constructor(
public name: string,
private age: number,
protected species: string,
) {}
// Methods
speak(): string { return `${this.name} makes a sound`; }
// Getters/setters
get humanAge(): number { return this.age * 7; }
// Static members
static create(name: string): Animal {
return new Animal(name, 0, 'unknown');
}
// Abstract
// abstract speak(): string; // In abstract class
// Access modifiers
// public, private, protected, readonly
}
// Implements interface
interface Serializable {
serialize(): string;
}
class User implements Serializable {
constructor(public name: string) {}
serialize(): string { return JSON.stringify({ name: this.name }); }
}
// Extends
class Dog extends Animal {
speak(): string { return `${this.name} barks`; }
override toString(): string { return this.name; } // `override` keyword
}
// Abstract class
abstract class Shape {
abstract area(): number;
describe(): string { return `Area: ${this.area()}`; }
}
Enums
// Numeric enum (avoid; prefer union types)
enum Direction { North, South, East, West }
// Direction.North === 0, etc.
// String enum (better than numeric)
enum Status {
Active = 'active',
Inactive = 'inactive',
}
// Const enum (inlined at compile time)
const enum Color { Red, Green, Blue }
// Union type alternative (preferred in modern TS)
type Direction = 'north' | 'south' | 'east' | 'west';
// Object literal alternative
const Status = {
Active: 'active',
Inactive: 'inactive',
} as const;
type Status = typeof Status[keyof typeof Status];
When to use: Enums are discouraged in modern TypeScript in favor of union types and as const objects. The exceptions are cases where you need a runtime object and the enum’s reverse mapping is useful.
keyof, typeof, Indexed Access
type User = { name: string; age: number; email: string };
// keyof: union of keys
type UserKey = keyof User; // 'name' | 'age' | 'email'
// typeof: type of a value
const user = { name: 'Rohit', age: 30 };
type UserType = typeof user; // { name: string; age: number }
// Indexed access: type of a property
type UserName = User['name']; // string
type UserValue = User[keyof User]; // string | number
// keyof + generic (get property)
function get<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
Conditional and Mapped Types
// Conditional
type IsArray<T> = T extends any[] ? true : false;
type ElementType<T> = T extends (infer U)[] ? U : never;
// Distributive conditional (applies per union member)
type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>; // string[] | number[]
// Mapped
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
// Remapping keys
type Nullable<T> = { [K in keyof T]: T[K] | null };
// Template literal + mapped
type Events<T> = {
[K in keyof T as `on${Capitalize<string & K>}Changed`]: (value: T[K]) => void;
};
tsconfig.json — Important Options
{
"compilerOptions": {
// Target and module
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler", // or "node16", "nodenext"
"lib": ["ES2022", "DOM", "DOM.Iterable"],
// Strictness (enable all)
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
// Extra safety
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
// Output
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": true,
// Interop and modules
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"resolveJsonModule": true,
"skipLibCheck": true,
// Paths
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
strict flag includes: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, alwaysStrict, useUnknownInCatchVariables.
Type Guards and Assertions
// Type assertion (unsafe; no runtime check)
const value = json as User;
// Non-null assertion (unsafe)
const name = user!.name;
// Type guard (safe; runtime check)
function isUser(x: unknown): x is User {
return typeof x === 'object' && x !== null && 'name' in x;
}
if (isUser(data)) {
data.name; // TypeScript knows it's User
}
// Assertion function (throws on failure)
function assertIsUser(x: unknown): asserts x is User {
if (!isUser(x)) throw new Error('Not a user');
}
// Unknown: safe alternative to any
function parse(input: unknown) {
if (typeof input === 'string') return input.toUpperCase();
if (typeof input === 'number') return input.toFixed(2);
return null;
}
unknown vs any: unknown requires narrowing before use; any permits anything. Prefer unknown for values of uncertain type (parsed JSON, error catches, third-party APIs).
Modules and Imports
// Named exports
export function add(a: number, b: number): number { return a + b; }
export const PI = 3.14;
export type User = { name: string };
// Default export
export default class Api { ... }
// Import
import Api, { add, PI, type User } from './api';
// Namespace import
import * as api from './api';
// Type-only import (erased at compile time)
import type { User } from './types';
// Re-export
export { add } from './math';
export type { User } from './types';
export * from './utils';
import type: guarantees the import is erased at runtime. Use it for types when isolatedModules or verbatimModuleSyntax is enabled.
Decorators (Standard, TS 5.0+)
// Class decorator
function sealed(target: Function) {
Object.seal(target);
Object.seal(target.prototype);
}
@sealed
class Greeter { ... }
// Method decorator
function log(target: any, key: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${key} with`, args);
return original.apply(this, args);
};
}
class Calculator {
@log
add(a: number, b: number): number { return a + b; }
}
Note: This is the standard decorator syntax (TS 5.0+). Legacy experimental decorators (used by Angular before v17) differ in signature and require experimentalDecorators: true.
Common Pitfalls
| Pitfall | Fix |
|---|---|
any everywhere | Use unknown and narrow |
Missing strict: true | Enable in tsconfig.json |
| Type assertions instead of guards | Write a type guard |
Non-null assertion ! abuse | Check for null/undefined |
| Using enums for simple unions | Prefer union types or as const |
Importing types without import type | Enables runtime imports |
as const on mutable objects | Use satisfies if widening not needed |
| Circular type references | Break with interfaces or lazy types |
| Optional chaining in type positions | Use conditional types |
Ignoring noUncheckedIndexedAccess | Enable it; handle undefined |
Visual: Type Narrowing Flow
┌──────────────────────────────────────────────┐
│ UNKNOWN VALUE → NARROWING │
│ │
│ let x: string | number | User │
│ │ │
│ ▼ │
│ typeof x === 'string' │
│ ├── true → x is string (narrowed) │
│ └── false → continue │
│ │ │
│ ▼ │
│ typeof x === 'number' │
│ ├── true → x is number │
│ └── false → continue │
│ │ │
│ ▼ │
│ 'name' in x │
│ ├── true → x is User │
│ └── false → x is never (exhausted) │
│ │
│ Control flow analysis tracks every branch. │
│ │
└──────────────────────────────────────────────┘
Summary
| Area | Key Takeaway |
|---|---|
| Primitives | string, number, boolean, bigint, symbol, null, undefined, never, unknown |
| Arrays/tuples | number[], [string, number], readonly variants |
| Unions | A | B; discriminated unions for exhaustive checks |
| Interfaces | Extendable, mergeable; type aliases for unions/mapped types |
| Generics | <T extends Constraint>; default, multiple, const type params |
| Utility types | Partial, Pick, Omit, Record, ReturnType, Awaited |
| Narrowing | typeof, instanceof, in, discriminants, type guards |
satisfies | Check conformance without widening |
| Classes | Parameter properties, access modifiers, override |
| Modules | import type, export type, isolatedModules |
tsconfig | strict: true, noUncheckedIndexedAccess, moduleResolution: bundler |
| Decorators | Standard syntax in TS 5.0+; legacy experimental for pre-Angular 17 |
TypeScript’s type system is a compile-time tool that erases at runtime. Every annotation, generic, and utility type is a compile-time constraint, not a runtime guarantee. The strict flag is the default you should enable in every project; the type system’s value comes from what it catches, not from what it documents. satisfies, as const, and discriminated unions are the modern patterns that replace type assertions and enums. The compiler is fast, the error messages are actionable, and the type system is powerful—use it.
TypeScript, cheatsheet, generics, utility types
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!