Back to Subjects
TypeScript Cheatsheet
Master TypeScript types, interfaces, generics, and advanced features for type-safe JavaScript development.
TypeScript Cheatsheet
Basic Types
// Primitive types
let str: string = "hello";
let num: number = 42;
let bool: boolean = true;
let n: null = null;
let u: undefined = undefined;
let sym: symbol = Symbol("key");
// Array types
let arr1: number[] = [1, 2, 3];
let arr2: Array<string> = ["a", "b", "c"];
let tuple: [string, number] = ["hello", 10];
// Object types
let obj: object = { x: 0 };
let any: any = "anything goes";
let unknown: unknown = "type-safe any";
let never: never; // represents unreachable code
Type Annotations
// Function parameters and return types
function add(x: number, y: number): number {
return x + y;
}
// Arrow functions
const multiply = (x: number, y: number): number => x * y;
// Optional parameters
function greet(name: string, greeting?: string): string {
return greeting ? `${greeting}, ${name}!` : `Hello, ${name}!`;
}
// Default parameters
function createUser(name: string, age: number = 18): object {
return { name, age };
}
// Rest parameters
function sum(...numbers: number[]): number {
return numbers.reduce((acc, num) => acc + num, 0);
}
Interfaces
// Basic interface
interface User {
id: number;
name: string;
email: string;
age?: number; // optional property
readonly createdAt: Date; // readonly property
}
// Implementing interface
class UserImpl implements User {
constructor(
public id: number,
public name: string,
public email: string,
public readonly createdAt: Date = new Date()
) {}
}
// Extending interfaces
interface Employee extends User {
role: string;
salary: number;
}
// Function interface
interface SearchFunc {
(source: string, subString: string): boolean;
}
// Indexable interface
interface StringArray {
[index: number]: string;
}
Classes
class Animal {
// Properties
private name: string;
protected species: string;
public age: number;
// Constructor
constructor(name: string, species: string, age: number = 0) {
this.name = name;
this.species = species;
this.age = age;
}
// Methods
public makeSound(): void {
console.log("Some sound");
}
protected getInfo(): string {
return `${this.name} is a ${this.species}`;
}
// Getter
get animalName(): string {
return this.name;
}
// Setter
set animalName(value: string) {
if (value.length > 0) {
this.name = value;
}
}
}
// Inheritance
class Dog extends Animal {
constructor(name: string, age: number) {
super(name, "Canis", age);
}
public makeSound(): void {
console.log("Woof!");
}
public wagTail(): void {
console.log("Tail wagging");
}
}
Generics
// Generic function
function identity<T>(arg: T): T {
return arg;
}
// Generic interface
interface Container<T> {
value: T;
getValue(): T;
}
// Generic class
class Queue<T> {
private data: T[] = [];
push(item: T): void {
this.data.push(item);
}
pop(): T | undefined {
return this.data.shift();
}
peek(): T | undefined {
return this.data[0];
}
}
// Generic constraints
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
// Multiple constraints
function combine<T extends object, U extends object>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
Union and Intersection Types
// Union types
type Status = "loading" | "success" | "error";
type ID = string | number;
function processId(id: ID): string {
if (typeof id === "string") {
return id.toUpperCase();
}
return id.toString();
}
// Intersection types
interface HasName {
name: string;
}
interface HasAge {
age: number;
}
type Person = HasName & HasAge;
const person: Person = {
name: "John",
age: 30
};
Type Guards
// Type guards
function isString(value: unknown): value is string {
return typeof value === "string";
}
function isNumber(value: unknown): value is number {
return typeof value === "number";
}
function isArray(value: unknown): value is any[] {
return Array.isArray(value);
}
// Usage
function processValue(value: unknown): string {
if (isString(value)) {
return value.toUpperCase();
}
if (isNumber(value)) {
return value.toString();
}
if (isArray(value)) {
return value.join(", ");
}
return "Unknown type";
}
Utility Types
// Partial - makes all properties optional
interface User {
name: string;
age: number;
email: string;
}
type PartialUser = Partial<User>;
// Equivalent to: { name?: string; age?: number; email?: string; }
// Required - makes all properties required
type RequiredUser = Required<PartialUser>;
// Pick - selects specific properties
type UserName = Pick<User, "name" | "email">;
// Omit - excludes specific properties
type UserWithoutEmail = Omit<User, "email">;
// Record - creates object type with specific keys and values
type UserRoles = Record<string, string[]>;
// ReturnType - extracts return type of function
type AddReturnType = ReturnType<typeof add>;
// Parameters - extracts parameter types of function
type AddParams = Parameters<typeof add>;
Advanced Types
// Conditional types
type NonNullable<T> = T extends null | undefined ? never : T;
type ArrayElement<T> = T extends Array<infer U> ? U : never;
// Mapped types
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
// Template literal types
type EventName<T extends string> = `${T}Changed`;
type Concat<S1 extends string, S2 extends string> = `${S1}${S2}`;
// Infer keyword
type ExtractReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
Enums
// Numeric enums
enum Direction {
Up = 0,
Down = 1,
Left = 2,
Right = 3
}
// String enums
enum Status {
Active = "ACTIVE",
Inactive = "INACTIVE",
Pending = "PENDING"
}
// Computed enums
enum FileAccess {
None = 0,
Read = 1 << 0,
Write = 1 << 1,
ReadWrite = Read | Write
}
Namespaces
namespace Validation {
export interface StringValidator {
isValid(s: string): boolean;
}
export class EmailValidator implements StringValidator {
isValid(s: string): boolean {
return s.includes("@");
}
}
}
// Usage
const validator = new Validation.EmailValidator();
Modules
// Exporting
export interface User {
id: number;
name: string;
}
export class UserService {
getUser(id: number): User | null {
// implementation
return null;
}
}
export default class Database {
// default export
}
// Importing
import { User, UserService } from "./user";
import Database from "./database";
import * as Utils from "./utils";
Best Practices
// Use strict mode
// tsconfig.json: "strict": true
// Prefer interfaces over type aliases for objects
interface Config {
apiUrl: string;
timeout: number;
}
// Use readonly for immutable properties
interface Point {
readonly x: number;
readonly y: number;
}
// Use const assertions
const colors = ["red", "green", "blue"] as const;
type Color = typeof colors[number];
// Avoid any, use unknown instead
function processData(data: unknown): void {
if (typeof data === "string") {
console.log(data.toUpperCase());
}
}
// Use branded types for type safety
type UserId = string & { readonly brand: unique symbol };
type ProductId = string & { readonly brand: unique symbol };
function getUser(id: UserId): User {
// implementation
}
Common Patterns
// Singleton pattern
class Singleton {
private static instance: Singleton;
private constructor() {}
static getInstance(): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
// Factory pattern
interface Product {
name: string;
price: number;
}
class ProductFactory {
static createProduct(type: string): Product {
switch (type) {
case "book":
return { name: "Book", price: 20 };
case "laptop":
return { name: "Laptop", price: 1000 };
default:
throw new Error("Unknown product type");
}
}
}
// Observer pattern
interface Observer {
update(data: any): void;
}
class Subject {
private observers: Observer[] = [];
attach(observer: Observer): void {
this.observers.push(observer);
}
notify(data: any): void {
this.observers.forEach(observer => observer.update(data));
}
}