Skip to content

TypeScript Cheat Sheet — The Essentials

Who this is for: A QA / test engineer who needs just enough TypeScript to read and write Playwright (or any TS) tests. Skim it once, keep it open as a reference. TypeScript = JavaScript + types (labels that catch mistakes before you run the code).


1. Why Types At All?

let count = 5;
count = "five";   // ❌ TypeScript error BEFORE you run — caught instantly

The type label means your editor flags typos, wrong arguments, and undefined bugs as you type, instead of 10 minutes into a test run.


2. Basic Types

let name: string = "Manoj";
let age: number = 42;
let isActive: boolean = true;
let nothing: null = null;
let notSet: undefined = undefined;
let anything: any = "avoid this";     // turns OFF type-checking — avoid

let id: number;          // declare type, assign later
id = 100;

// Arrays
let scores: number[] = [90, 85, 100];
let names: string[] = ["a", "b"];

// Tuple — fixed-length, typed positions
let pair: [string, number] = ["age", 42];

3. Type Inference (you often don't need to write types)

let city = "London";     // TS infers: string
let total = 10 + 5;      // TS infers: number
// city = 42;            // ❌ still caught, even without an explicit type

Rule of thumb: let TS infer simple variables; write explicit types on function parameters and object shapes.


4. Functions

// parameter types + return type
function add(a: number, b: number): number {
  return a + b;
}

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

// optional parameter (?)  and  default value
function log(msg: string, level?: string) {}          // level may be undefined
function pageSize(n: number = 20): number { return n; } // default 20

// returns nothing
function printIt(x: string): void {
  console.log(x);
}

// async function returns a Promise
async function fetchUser(id: number): Promise<string> {
  return "user";
}

5. Objects, type, and interface

Two ways to describe an object's shape. Both work; interface is common for objects, type for everything (unions, primitives, etc.).

// interface
interface User {
  name: string;
  age: number;
  email?: string;        // optional
  readonly id: number;   // can't be reassigned after creation
}

// type alias
type Point = { x: number; y: number };

const u: User = { name: "Jane", age: 30, id: 1 };
const p: Point = { x: 10, y: 20 };
interface type
Describe object shape
Unions (A \| B)
Can be extended/merged ✅ (re-declare) via &
Common use Objects, classes Unions, primitives, functions

6. Union & Literal Types

let id: string | number;     // EITHER a string OR a number
id = "abc";  id = 123;       // both fine

// literal union — only these exact values allowed
type Status = "pass" | "fail" | "skip";
let result: Status = "pass";
// result = "broken";        // ❌ not an allowed value

This is huge for tests: reporter: "html" | "list" | "junit" stops typos at write time.


7. Arrays of Objects & Record

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

const cases: TestCase[] = [
  { id: 1, name: "login" },
  { id: 2, name: "logout" },
];

// Record<Keys, ValueType> — a typed dictionary/map
const env: Record<string, string> = {
  BASE_URL: "https://staging",
  TOKEN: "abc123",
};

8. Classes (Page Objects use these)

class LoginPage {
  // properties with access modifiers
  private url: string;
  readonly name: string = "Login";

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

  // method
  open(): void {
    console.log(`Opening ${this.url}`);
  }
}

// inheritance
class AdminPage extends LoginPage {
  constructor() {
    super("/admin");
  }
}

const page = new LoginPage("/login");
page.open();
Modifier Meaning
public (default) Accessible anywhere
private Only inside this class
protected This class + subclasses
readonly Set once, never reassigned

9. Generics — <T> (reusable, type-safe code)

A placeholder type filled in when used. You'll read these constantly in Playwright (Promise<void>, Locator, test.extend<MyFixtures>).

function first<T>(items: T[]): T {
  return items[0];
}

first<number>([1, 2, 3]);   // T = number → returns number
first(["a", "b"]);          // T inferred as string

// Promise<T> — an async value of type T
async function getCount(): Promise<number> {
  return 5;
}

10. Handling null / undefined (the safety stuff)

let val: string | undefined;

// optional chaining ?.  — stop if null/undefined, don't crash
const len = val?.length;            // number | undefined

// nullish coalescing ??  — fallback ONLY when null/undefined
const name = val ?? "default";      // "default" if val is null/undefined

// non-null assertion !  — "trust me, it's not null" (use sparingly)
const sure = val!.length;           // tells TS to stop worrying

11. Imports & Exports (how files connect)

// named export
export const BASE_URL = "https://app.com";
export function login() {}

// import named things
import { BASE_URL, login } from "./config";

// default export (one per file)
export default class LoginPage {}
import LoginPage from "./LoginPage";

// import everything
import * as utils from "./utils";

// type-only import (clarity / perf)
import type { User } from "./types";

12. Common Playwright + TypeScript Patterns

import { test, expect, Page, Locator } from '@playwright/test';

// typed Page Object
class CartPage {
  readonly checkoutBtn: Locator;
  constructor(public page: Page) {
    this.checkoutBtn = page.getByRole('button', { name: 'Checkout' });
  }
  async checkout(): Promise<void> {
    await this.checkoutBtn.click();
  }
}

// async/await — almost everything in Playwright is async
test('adds item', async ({ page }) => {
  await page.goto('/');                 // await = wait for it to finish
  const title: string = await page.title();
  expect(title).toContain('Shop');
});

// typed test data array (data-driven)
const users: { name: string; valid: boolean }[] = [
  { name: 'standard', valid: true },
  { name: 'locked',   valid: false },
];

for (const u of users) {
  test(`login: ${u.name}`, async ({ page }) => { /* ... */ });
}

13. Quick Symbol Reference

Symbol Meaning Example
: type annotation name: string
? optional email?: string
\| union (or) string \| number
& intersection (and) A & B
=> arrow function (x) => x + 1
?. optional chaining user?.name
?? nullish fallback x ?? "default"
! non-null assertion value!
<T> generic type Array<string>
readonly can't reassign readonly id: number
as type assertion x as string
... spread / rest [...arr], (...args)
`${}` template string `Hi ${name}`

14. The 5 Things You'll Use 90% of the Time

  1. async / await — Playwright is asynchronous; almost every action needs await.
  2. interface / type — describe your test data and page shapes.
  3. Union literals"pass" | "fail" to constrain values.
  4. Classes — Page Objects are classes.
  5. ?. and ?? — handle values that might be missing without crashing.

15. Where to Go Next