TypeScript Arrays — Complete Guide with map, filter, reduce & Playwright Examples

Arrays are everywhere in test automation — storing test data, collecting page elements, managing results. TypeScript arrays come with strong typing that catches bugs before your tests even run. This guide covers everything from basics to advanced patterns with Playwright examples.

📖 What You’ll Learn: Array types, push/pop/splice, map/filter/reduce, spread operator, tuples, readonly arrays, and array operations in Playwright tests.


đŸ“Ļ Declaring Arrays

// Two ways to declare typed arrays
let browsers: string[] = ['chromium', 'firefox', 'webkit'];
let scores: Array<number> = [85, 92, 78, 95];

// Mixed types with union
let mixed: (string | number)[] = ['hello', 42, 'world'];

// Empty array with type
let results: boolean[] = [];

// Array of objects
let users: { name: string; role: string }[] = [
  { name: 'Deepesh', role: 'SDET' },
  { name: 'John', role: 'QA Lead' },
];

// 2D array (matrix)
let grid: number[][] = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

➕ Adding & Removing Elements

let fruits: string[] = ['apple', 'banana'];

// Add to end
fruits.push('cherry');           // ['apple', 'banana', 'cherry']

// Add to beginning
fruits.unshift('mango');         // ['mango', 'apple', 'banana', 'cherry']

// Remove from end
let last = fruits.pop();         // 'cherry', array: ['mango', 'apple', 'banana']

// Remove from beginning
let first = fruits.shift();      // 'mango', array: ['apple', 'banana']

// Remove/insert at position with splice
let colors: string[] = ['red', 'green', 'blue', 'yellow'];
colors.splice(1, 2);             // Remove 2 items from index 1 → ['red', 'yellow']
colors.splice(1, 0, 'purple');   // Insert at index 1 → ['red', 'purple', 'yellow']

// Find index and remove
let items = ['a', 'b', 'c', 'd'];
let idx = items.indexOf('c');
if (idx !== -1) items.splice(idx, 1);  // ['a', 'b', 'd']

🔍 Searching & Checking Arrays

let numbers: number[] = [10, 20, 30, 40, 50];

// includes — does it contain a value?
console.log(numbers.includes(30));  // true

// indexOf — find position (-1 if not found)
console.log(numbers.indexOf(40));   // 3

// find — first element matching condition
let found = numbers.find(n => n > 25);
console.log(found);  // 30

// findIndex — index of first match
let foundIdx = numbers.findIndex(n => n > 25);
console.log(foundIdx);  // 2

// every — do ALL elements match?
let allPositive = numbers.every(n => n > 0);    // true

// some — does ANY element match?
let hasLarge = numbers.some(n => n > 100);       // false

🔄 map, filter & reduce

let prices: number[] = [100, 200, 300, 400, 500];

// map — transform each element
let discounted = prices.map(p => p * 0.9);
console.log(discounted);  // [90, 180, 270, 360, 450]

// filter — keep elements matching condition
let expensive = prices.filter(p => p >= 300);
console.log(expensive);  // [300, 400, 500]

// reduce — combine all elements into one value
let total = prices.reduce((sum, p) => sum + p, 0);
console.log(total);  // 1500

// Chaining — filter + map + reduce
let premiumTotal = prices
  .filter(p => p >= 300)           // [300, 400, 500]
  .map(p => p * 1.1)               // [330, 440, 550]
  .reduce((sum, p) => sum + p, 0); // 1320
console.log(premiumTotal);

// flat — flatten nested arrays
let nested: number[][] = [[1, 2], [3, 4], [5]];
let flat = nested.flat();
console.log(flat);  // [1, 2, 3, 4, 5]

💡 map transforms, filter selects, reduce combines. Chain them together for powerful data pipelines. These are the three most important array methods to master.


📌 Spread, Destructuring & Tuples

// Spread operator — copy and merge arrays
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let combined = [...arr1, ...arr2];    // [1, 2, 3, 4, 5, 6]
let copy = [...arr1];                 // [1, 2, 3] — independent copy

// Destructuring — extract values
let [first, second, ...rest] = [10, 20, 30, 40, 50];
console.log(first);  // 10
console.log(rest);   // [30, 40, 50]

// Tuple — fixed-length, typed array
let coord: [number, number] = [40.7128, -74.0060];
let entry: [string, number, boolean] = ['test-1', 95, true];

// Readonly array — cannot be modified
const readonlyBrowsers: readonly string[] = ['chromium', 'firefox', 'webkit'];
// readonlyBrowsers.push('edge');  // ❌ Error! Cannot modify

// Sorting
let nums = [30, 10, 50, 20, 40];
nums.sort((a, b) => a - b);          // [10, 20, 30, 40, 50] ascending
nums.sort((a, b) => b - a);          // [50, 40, 30, 20, 10] descending

🎭 Arrays in Playwright — Real Examples

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

test('collect and verify all product names', async ({ page }) => {
  await page.goto('https://sqatools.in');
  
  // Collect all text content into an array
  const links = page.locator('nav a');
  const texts: string[] = await links.allTextContents();
  
  console.log('Navigation links:', texts);
  expect(texts.length).toBeGreaterThan(0);
  
  // Filter only links containing 'Playwright'
  const playwrightLinks = texts.filter(t => t.toLowerCase().includes('playwright'));
  console.log('Playwright links:', playwrightLinks);
});

// Data-driven testing with arrays
const testData: [string, string, boolean][] = [
  ['admin@test.com', 'admin123', true],
  ['invalid@test.com', 'wrong', false],
  ['', '', false],
];

for (const [email, password, shouldPass] of testData) {
  test(`login with ${email || 'empty'} should ${shouldPass ? 'pass' : 'fail'}`, async ({ page }) => {
    await page.goto('/login');
    await page.fill('#email', email);
    await page.fill('#password', password);
    await page.click('#submit');
    
    if (shouldPass) {
      await expect(page.locator('.dashboard')).toBeVisible();
    } else {
      await expect(page.locator('.error')).toBeVisible();
    }
  });
}

❓ FAQ

🤔 What is the difference between string[] and Array<string>?

They are identical — both declare an array of strings. string[] is shorter and more commonly used. Array<string> is clearer for complex types like Array<Map<string, number>>.


🤔 How do I get all text from Playwright locators into an array?

Use await locator.allTextContents() — it returns a string[] with the text content of every matching element. For inner text, use allInnerTexts().

đŸŽ¯ Next Steps

đŸŽŦ Watch the full TypeScript tutorial series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

TypeScript Functions — Declarations, Arrow Functions, Async & Generics with Playwright

Functions are the building blocks of clean, reusable code. In test automation, you’ll use them everywhere — from page actions to custom assertions to utility helpers. This guide covers every function pattern in TypeScript with real Playwright examples.

📖 What You’ll Learn: Function declarations, arrow functions, optional & default parameters, rest parameters, return types, overloads, generics in functions, and async functions in Playwright.


🔧 Function Declarations & Expressions

// Function declaration
function greet(name: string): string {
  return `Hello, ${name}!`;
}

// Function expression
const add = function(a: number, b: number): number {
  return a + b;
};

// Arrow function (most common in modern TypeScript)
const multiply = (a: number, b: number): number => a * b;

// Void function — returns nothing
function logMessage(msg: string): void {
  console.log(`[LOG]: ${msg}`);
}

console.log(greet('QA Engineer'));  // Hello, QA Engineer!
console.log(add(5, 3));            // 8
console.log(multiply(4, 7));       // 28

âš™ī¸ Optional, Default & Rest Parameters

// Optional parameter (use ?)
function createUser(name: string, email?: string): string {
  return email ? `${name} (${email})` : name;
}
console.log(createUser('Deepesh'));                    // Deepesh
console.log(createUser('Deepesh', 'test@test.com'));   // Deepesh (test@test.com)

// Default parameter
function wait(ms: number = 1000): void {
  console.log(`Waiting ${ms}ms...`);
}
wait();      // Waiting 1000ms...
wait(3000);  // Waiting 3000ms...

// Rest parameters (variable number of args)
function logAll(...messages: string[]): void {
  messages.forEach((msg, i) => console.log(`${i + 1}. ${msg}`));
}
logAll('Step 1', 'Step 2', 'Step 3');

// Destructured parameters
function printConfig({ url, timeout = 30000 }: { url: string; timeout?: number }): void {
  console.log(`URL: ${url}, Timeout: ${timeout}`);
}
printConfig({ url: 'https://sqatools.in' });

📝 Function Types & Callbacks

// Type alias for a function
type Validator = (value: string) => boolean;

const isEmail: Validator = (value) => value.includes('@');
const isNotEmpty: Validator = (value) => value.trim().length > 0;

console.log(isEmail('test@test.com'));  // true
console.log(isNotEmpty(''));            // false

// Callback functions
function runValidation(input: string, validator: Validator, onResult: (passed: boolean) => void): void {
  const result = validator(input);
  onResult(result);
}

runValidation('hello@test.com', isEmail, (passed) => {
  console.log(passed ? '✅ Valid' : '❌ Invalid');
});

// Returning functions (higher-order)
function createMultiplier(factor: number): (n: number) => number {
  return (n) => n * factor;
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5));  // 10
console.log(triple(5));  // 15

đŸ§Ŧ Generic Functions

// Generic function — works with any type
function firstElement<T>(arr: T[]): T | undefined {
  return arr[0];
}

console.log(firstElement([1, 2, 3]));          // 1 (type: number)
console.log(firstElement(['a', 'b', 'c']));    // 'a' (type: string)

// Generic with constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: 'Deepesh', role: 'SDET' };
console.log(getProperty(user, 'name'));  // 'Deepesh'

// Generic async function
async function fetchData<T>(url: string): Promise<T> {
  const response = await fetch(url);
  return response.json() as Promise<T>;
}

💡 Generics let you write ONE function that works with strings, numbers, objects — anything. TypeScript figures out the type automatically when you call it.


⚡ Async Functions

// Async function returns a Promise
async function fetchTitle(url: string): Promise<string> {
  const response = await fetch(url);
  const html = await response.text();
  const match = html.match(/<title>(.*)<\/title>/);
  return match ? match[1] : 'No title found';
}

// Async arrow function
const delay = async (ms: number): Promise<void> => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

// Try-catch in async functions
async function safeRequest(url: string): Promise<string | null> {
  try {
    const response = await fetch(url);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return await response.text();
  } catch (error) {
    console.error('Request failed:', error);
    return null;
  }
}

🎭 Functions in Playwright — Real Examples

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

// Reusable login helper function
async function login(page: Page, email: string, password: string): Promise<void> {
  await page.goto('/login');
  await page.fill('#email', email);
  await page.fill('#password', password);
  await page.click('#login-btn');
  await expect(page.locator('.dashboard')).toBeVisible();
}

// Retry function for flaky operations
async function retry<T>(fn: () => Promise<T>, maxAttempts: number = 3): Promise<T> {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (attempt === maxAttempts) throw error;
      console.log(`Attempt ${attempt} failed, retrying...`);
      await new Promise(r => setTimeout(r, 1000));
    }
  }
  throw new Error('Should not reach here');
}

// Using helper functions in tests
test('login and verify dashboard', async ({ page }) => {
  await login(page, 'admin@sqatools.in', 'test123');
  await expect(page).toHaveTitle(/Dashboard/);
});

test('retry flaky element click', async ({ page }) => {
  await page.goto('https://sqatools.in');
  await retry(async () => {
    await page.click('.dynamic-button');
    await expect(page.locator('.result')).toBeVisible();
  });
});

❓ FAQ

🤔 When should I use arrow functions vs regular functions?

Use arrow functions for callbacks, short expressions, and class methods. Use regular functions when you need hoisting or a named function in stack traces. In Playwright, arrow functions are standard for test callbacks and helpers.


🤔 What is the difference between optional and default parameters?

Optional parameters (name?: string) can be omitted and will be undefined. Default parameters (name: string = 'Guest') have a fallback value when omitted. Default parameters are preferred when you have a sensible default.

đŸŽ¯ Next Steps

đŸŽŦ Watch the full TypeScript tutorial series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

TypeScript Loops — for, while, for…of & forEach with Playwright Examples

Loops let you repeat actions — whether it’s iterating through test data, checking multiple elements, or retrying flaky operations. This guide covers every loop type in TypeScript with real Playwright examples you’ll use daily in test automation.

📖 What You’ll Learn: for loop, while loop, do…while, for…of, for…in, forEach, break/continue, and looping through Playwright elements.


🔁 for Loop

The classic loop — you control the start, end, and step.

// Basic for loop
for (let i: number = 0; i < 5; i++) {
  console.log('Iteration:', i);
}
// Output: 0, 1, 2, 3, 4

// Counting backwards
for (let i: number = 10; i > 0; i -= 2) {
  console.log(i);
}
// Output: 10, 8, 6, 4, 2

// Looping through an array by index
let browsers: string[] = ['chromium', 'firefox', 'webkit'];
for (let i = 0; i < browsers.length; i++) {
  console.log(`Browser ${i + 1}: ${browsers[i]}`);
}

🔄 while and do...while Loops

// while — checks condition BEFORE each iteration
let attempts: number = 0;
while (attempts < 3) {
  console.log(`Attempt ${attempts + 1}`);
  attempts++;
}

// do...while — runs at least ONCE, then checks condition
let input: string = '';
do {
  input = 'valid';  // simulating user input
  console.log('Processing input:', input);
} while (input === '');

// Retry pattern (common in test automation)
let retryCount: number = 0;
let success: boolean = false;
while (!success && retryCount < 3) {
  try {
    // attempt some operation
    success = true;
    console.log('Operation succeeded!');
  } catch {
    retryCount++;
    console.log(`Retry ${retryCount}/3`);
  }
}

âš ī¸ Always include a way to exit while loops (increment a counter, set a flag). An infinite loop will crash your tests!


đŸŽ¯ for...of and for...in Loops

// for...of — iterate over VALUES (arrays, strings, maps)
let testCases: string[] = ['login', 'signup', 'checkout'];
for (const tc of testCases) {
  console.log('Running test:', tc);
}

// for...in — iterate over KEYS/INDICES (objects)
let config = { baseURL: 'https://sqatools.in', timeout: 30000, retries: 2 };
for (const key in config) {
  console.log(`${key}: ${config[key as keyof typeof config]}`);
}

// Iterating over a Map
let testData = new Map();
testData.set('user1', 'admin@test.com');
testData.set('user2', 'user@test.com');

for (const [key, value] of testData) {
  console.log(`${key} -> ${value}`);
}

💡 Quick Rule: Use for...of for arrays and iterable values. Use for...in for object keys. Never use for...in on arrays — it iterates over indices as strings, which causes bugs.


📋 forEach and Array Methods

let scores: number[] = [85, 92, 78, 95, 88];

// forEach — run a function for each element
scores.forEach((score, index) => {
  console.log(`Student ${index + 1}: ${score}`);
});

// map — transform each element into a new array
let grades = scores.map(s => s >= 90 ? 'A' : s >= 80 ? 'B' : 'C');
console.log(grades);  // ['B', 'A', 'C', 'A', 'B']

// filter — keep only elements that match
let topScores = scores.filter(s => s >= 90);
console.log(topScores);  // [92, 95]

// find — get the first match
let firstTop = scores.find(s => s >= 90);
console.log(firstTop);  // 92

// every/some — check all or any
let allPassed = scores.every(s => s >= 60);   // true
let anyPerfect = scores.some(s => s === 100); // false

âšī¸ break and continue

// break — exit the loop entirely
for (let i = 0; i < 10; i++) {
  if (i === 5) break;
  console.log(i);
}
// Output: 0, 1, 2, 3, 4

// continue — skip current iteration, go to next
for (let i = 0; i < 10; i++) {
  if (i % 2 === 0) continue;  // skip even numbers
  console.log(i);
}
// Output: 1, 3, 5, 7, 9

🎭 Loops in Playwright — Real Examples

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

test('iterate through page elements', async ({ page }) => {
  await page.goto('https://sqatools.in');
  
  // Get all navigation links and verify each one
  const navLinks = page.locator('nav a');
  const count = await navLinks.count();
  
  for (let i = 0; i < count; i++) {
    const text = await navLinks.nth(i).textContent();
    const href = await navLinks.nth(i).getAttribute('href');
    console.log(`Link ${i + 1}: ${text} -> ${href}`);
    expect(href).not.toBeNull();
  }
});

// Data-driven test with for...of
const testUsers = [
  { email: 'admin@test.com', role: 'admin' },
  { email: 'user@test.com', role: 'user' },
  { email: 'guest@test.com', role: 'guest' },
];

for (const user of testUsers) {
  test(`login as ${user.role}`, async ({ page }) => {
    await page.goto('/login');
    await page.fill('#email', user.email);
    await page.fill('#password', 'test123');
    await page.click('#login-btn');
    await expect(page.locator('.role-badge')).toHaveText(user.role);
  });
}

❓ FAQ

🤔 What is the difference between for...of and for...in?

for...of iterates over values (arrays, strings). for...in iterates over keys/indices (objects). Use for...of for arrays and for...in for object properties.


🤔 How do I loop through Playwright locators?

Use locator.count() to get the number of matches, then use a for loop with locator.nth(i) to access each element individually.

đŸŽ¯ Next Steps

đŸŽŦ Watch the full TypeScript tutorial series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

TypeScript Conditions — if/else, Switch & Type Guards with Playwright Examples

Conditions let you control which code runs based on different scenarios — essential for building smart Playwright tests that handle popups, dynamic content, and different environments. This guide covers if/else, switch, ternary operators, and type guards with real test automation examples.

📖 What You’ll Learn: if/else statements, else if chains, switch/case, ternary operator, type narrowing with conditions, and real Playwright conditional flows.


🔀 if / else Statement

The most basic conditional — execute code only when a condition is true.

let temperature: number = 30;

if (temperature > 25) {
  console.log("It's hot outside! â˜€ī¸");
} else {
  console.log("It's cool outside! đŸŒ¤ī¸");
}
// Output: "It's hot outside! â˜€ī¸"

🔗 else if Chain

Check multiple conditions in sequence — the first match wins.

let score: number = 85;
let grade: string;

if (score >= 90) {
  grade = "A — Excellent!";
} else if (score >= 80) {
  grade = "B — Good job!";
} else if (score >= 70) {
  grade = "C — Average";
} else if (score >= 60) {
  grade = "D — Below average";
} else {
  grade = "F — Needs improvement";
}

console.log(grade);  // "B — Good job!"

💡 Tip: Order your conditions from most specific to least specific. TypeScript evaluates them top-to-bottom and stops at the first match.


🔄 Switch Statement

When you have many possible values for a single variable, switch is cleaner than multiple if/else statements.

type Browser = 'chromium' | 'firefox' | 'webkit';
let browserName: Browser = 'chromium';

switch (browserName) {
  case 'chromium':
    console.log('🌐 Running on Chrome/Edge');
    break;
  case 'firefox':
    console.log('đŸĻŠ Running on Firefox');
    break;
  case 'webkit':
    console.log('🧭 Running on Safari');
    break;
  default:
    console.log('❓ Unknown browser');
}

// Switch with return (in a function)
function getTimeout(env: string): number {
  switch (env) {
    case 'production': return 30000;
    case 'staging':    return 15000;
    case 'local':      return 5000;
    default:           return 10000;
  }
}

⚡ Ternary Operator

A one-liner alternative to if/else — perfect for simple conditions.

// Syntax: condition ? valueIfTrue : valueIfFalse

let isProduction: boolean = false;
let baseURL = isProduction ? 'https://app.com' : 'https://staging.app.com';

let userAge: number = 20;
let category = userAge >= 18 ? 'Adult' : 'Minor';

// Nested ternary (use sparingly!)
let speed: number = 100;
let zone = speed > 120 ? 'Danger' : speed > 80 ? 'Fast' : 'Normal';

âš ī¸ Avoid nested ternaries — they’re hard to read. Use if/else instead when the logic is complex.


🔍 Type Narrowing with Conditions

TypeScript gets smarter inside conditional blocks — it narrows the type automatically.

// typeof narrowing
function formatValue(value: string | number): string {
  if (typeof value === 'string') {
    return value.toUpperCase();  // TypeScript knows it's a string here
  } else {
    return value.toFixed(2);     // TypeScript knows it's a number here
  }
}

// Truthiness narrowing
function greetUser(name: string | null | undefined): string {
  if (name) {
    return 'Hello, ' + name;   // name is definitely a string here
  }
  return 'Hello, Guest';
}

// in operator narrowing
interface Dog { bark(): void; breed: string; }
interface Cat { meow(): void; color: string; }

function handlePet(pet: Dog | Cat) {
  if ('bark' in pet) {
    pet.bark();    // TypeScript knows it's a Dog
  } else {
    pet.meow();    // TypeScript knows it's a Cat
  }
}

🎭 Conditions in Playwright — Real Examples

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

test('handle dynamic page content', async ({ page }) => {
  await page.goto('https://sqatools.in');
  
  // Close popup if it appears
  const popup = page.locator('.popup-overlay');
  if (await popup.isVisible({ timeout: 3000 }).catch(() => false)) {
    await popup.locator('.close-btn').click();
    console.log('Popup closed');
  }
  
  // Environment-based navigation
  const env = process.env.TEST_ENV ?? 'staging';
  switch (env) {
    case 'production':
      await page.goto('https://sqatools.in');
      break;
    case 'staging':
      await page.goto('https://staging.sqatools.in');
      break;
    default:
      await page.goto('http://localhost:3000');
  }
  
  // Conditional assertions based on page state
  const loginBtn = page.locator('#login-btn');
  const dashboardLink = page.locator('#dashboard');
  
  if (await loginBtn.isVisible()) {
    console.log('User is not logged in');
    await loginBtn.click();
  } else if (await dashboardLink.isVisible()) {
    console.log('User is already logged in');
  }
});

❓ FAQ

🤔 When should I use switch vs if/else?

Use switch when comparing a single variable against multiple specific values. Use if/else when conditions are complex expressions or involve multiple variables.


🤔 What is type narrowing in TypeScript?

Type narrowing is when TypeScript automatically narrows a union type to a more specific type inside a conditional block. For example, after if (typeof x === 'string'), TypeScript knows x is a string.

đŸŽ¯ Next Steps

đŸŽŦ Watch the full TypeScript tutorial series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

TypeScript Operators — Complete Guide with Playwright Examples

Operators are the building blocks of every TypeScript program. Whether you’re writing Playwright test automation or building applications, understanding operators is essential. This guide covers every operator type in TypeScript with practical examples you can use in your Playwright projects.

📖 What You’ll Learn: Arithmetic, Comparison, Logical, Assignment, Ternary, Nullish Coalescing, and Type operators — all with real Playwright examples.


➕ Arithmetic Operators

Arithmetic operators perform mathematical calculations on numbers.

let a: number = 10;
let b: number = 3;

console.log(a + b);   // 13  — Addition
console.log(a - b);   // 7   — Subtraction
console.log(a * b);   // 30  — Multiplication
console.log(a / b);   // 3.33 — Division
console.log(a % b);   // 1   — Modulus (remainder)
console.log(a ** b);  // 1000 — Exponentiation

// Increment and Decrement
let count: number = 5;
count++;   // 6 (post-increment)
count--;   // 5 (post-decrement)
++count;   // 6 (pre-increment)

âš–ī¸ Comparison Operators

Comparison operators compare two values and return a boolean (true or false). These are essential in Playwright assertions.

let x: number = 5;
let y: string = "5";

// Loose equality (compares value only, allows type coercion)
console.log(x == y);    // true — NOT recommended in TypeScript

// Strict equality (compares value AND type)
console.log(x === 5);   // true — ALWAYS use this
console.log(x === y);   // Error! TypeScript catches this at compile time

// Not equal
console.log(x != y);    // false (loose)
console.log(x !== 10);  // true (strict)

// Greater / Less than
console.log(x > 3);     // true
console.log(x >= 5);    // true
console.log(x < 10);    // true
console.log(x <= 4);    // false

âš ī¸ Golden Rule: Always use === (strict equality) and !== in TypeScript. The loose operators == and != can cause subtle bugs that are hard to debug in test automation.


🧠 Logical Operators

Logical operators combine multiple conditions. You'll use these constantly in test automation for complex validations.

let isLoggedIn: boolean = true;
let isAdmin: boolean = false;
let hasPermission: boolean = true;

// AND (&&) — ALL conditions must be true
console.log(isLoggedIn && isAdmin);         // false
console.log(isLoggedIn && hasPermission);    // true

// OR (||) — at least ONE must be true
console.log(isAdmin || hasPermission);       // true

// NOT (!) — reverses the boolean
console.log(!isLoggedIn);                    // false
console.log(!isAdmin);                       // true

// Combining multiple operators
if (isLoggedIn && (isAdmin || hasPermission)) {
  console.log("Access granted");  // This runs
}

📝 Assignment Operators

let num: number = 10;

num += 5;   // num = num + 5  → 15
num -= 3;   // num = num - 3  → 12
num *= 2;   // num = num * 2  → 24
num /= 4;   // num = num / 4  → 6
num %= 4;   // num = num % 4  → 2
num **= 3;  // num = num ** 3 → 8

❓ Ternary & Nullish Coalescing Operators

These are shorthand operators that make your code cleaner and more readable.

// Ternary Operator: condition ? valueIfTrue : valueIfFalse
let age: number = 20;
let status: string = age >= 18 ? "Adult" : "Minor";
console.log(status);  // "Adult"

// Nullish Coalescing (??) — returns right side if left is null/undefined
let username: string | null = null;
let displayName = username ?? "Guest";
console.log(displayName);  // "Guest"

// Optional Chaining (?.) — safely access nested properties
interface User {
  name: string;
  address?: { city?: string };
}
let user: User = { name: "Deepesh" };
console.log(user.address?.city);  // undefined (no error!)

🔍 Type Operators (TypeScript-Specific)

// typeof — check runtime type
let value: unknown = "hello";
if (typeof value === "string") {
  console.log(value.toUpperCase());  // "HELLO"
}

// instanceof — check if object is an instance of a class
class Animal { name: string = "dog"; }
class Dog extends Animal { breed: string = "lab"; }

let pet = new Dog();
console.log(pet instanceof Dog);     // true
console.log(pet instanceof Animal);  // true

// keyof — get union of object keys (compile-time only)
interface Config {
  baseURL: string;
  timeout: number;
}
type ConfigKey = keyof Config;  // "baseURL" | "timeout"

// as — type assertion
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;

🎭 Operators in Playwright — Real Examples

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

test('using operators in Playwright tests', async ({ page }) => {
  await page.goto('https://sqatools.in');
  
  // Comparison: check element count
  const links = await page.locator('a').count();
  expect(links > 0).toBeTruthy();
  
  // Logical: multiple conditions
  const title = await page.title();
  const isCorrectPage = title.includes('SQA') && links > 10;
  expect(isCorrectPage).toBe(true);
  
  // Nullish coalescing: safe text extraction
  const headerText = await page.locator('h1').first().textContent() ?? '';
  expect(headerText.length > 0).toBeTruthy();
  
  // Ternary: conditional actions
  const env = process.env.ENV ?? 'staging';
  const timeout = env === 'production' ? 30000 : 10000;
  
  // typeof: type guards for safe handling
  const attribute = await page.locator('body').getAttribute('class');
  if (typeof attribute === 'string') {
    console.log('Body classes:', attribute);
  }
});

❓ FAQ

🤔 What is the difference between == and === in TypeScript?

== compares values with type coercion (loose equality), while === compares both value and type (strict equality). Always use === in TypeScript.


🤔 What is the nullish coalescing operator (??) in TypeScript?

The ?? operator returns the right-hand value when the left-hand value is null or undefined. Unlike ||, it doesn't treat 0, "", or false as "empty".


🤔 How do I use typeof in Playwright tests?

Use typeof to check the runtime type of values returned from page methods. For example, typeof (await page.title()) === 'string' ensures you're working with a string before calling string methods.

đŸŽ¯ Next Steps

Now that you understand TypeScript operators, continue your learning journey:

đŸŽŦ Watch the full TypeScript tutorial series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in