DEV Community

Cover image for ๐Ÿ—บ๏ธ Your First Steps in TypeScript: A Practical Roadmap for Automation QA
idavidov13
idavidov13

Posted on • Edited on • Originally published at idavidov.eu

๐Ÿ—บ๏ธ Your First Steps in TypeScript: A Practical Roadmap for Automation QA

Ever had a test fail at a critical moment due to a simple typo in a variable or an unexpected API response? Weโ€™ve all been there. These runtime errors are frustrating and time-consuming. This is where TypeScript comes in.

For QA Testers, TypeScript is more than just a programming language - itโ€™s a safety net. It helps you catch bugs before you run your tests, not during. This article is your starting point. We'll cover the essentials you need to start writing more robust and reliable automated tests today.


โœ… Prerequisites

While experience with JavaScript, Playwright, or Cypress is beneficial, itโ€™s not required. Weโ€™ll explain everything in a simple way, making this a great starting point even for beginners.


๐Ÿค” The โ€œWhyโ€: Catching Bugs Before They Happen

TS is your safety net
Imagine you're testing an API. You expect a response body with a user's id and username. In JavaScript, you might write a test like this:

const userId = response.body.id;
const userPassword = response.body.password; // Oops!
Enter fullscreen mode Exit fullscreen mode

Your test would run, and only then would it fail because response.body.password is undefined. Itโ€™s a bug in your code, but you only found it at runtime.

With TypeScript, you would first define the shape of your expected data. If you tried to access .passwordโ€”a key that doesn't exist in your defined shapeโ€”TypeScript would show an error right in your code editor. You fix the bug before the test even runs. This is the core power of TypeScript: adding confidence and preventing errors.


๐Ÿงฑ The Building Blocks: Core Types

Image description
At its heart, TypeScript is about adding type annotations to your variables. Think of it as giving every variable a specific job description.

A string is used for text data, like URLs, locators, or messages.

const blogURL: string = 'https://idavidov.eu/';
Enter fullscreen mode Exit fullscreen mode

In testing, you'll use strings constantly for base URLs, selectors, and test data. Typing them ensures you don't accidentally try to perform a mathematical operation on a URL!

A number is for, well, numbers! This includes integers and decimals.

const expectedItemCount: number = 13;
Enter fullscreen mode Exit fullscreen mode

This is perfect for asserting an expected element count, checking API status codes (200, 404), or verifying prices.

A boolean can only be true or false. Itโ€™s the ultimate "yes or no."

const isButtonEnabled: boolean = true;
Enter fullscreen mode Exit fullscreen mode

Booleans are essential for checking the state of UI elements. Is a checkbox ticked? Is a button visible? Is a toggle on? A boolean gives you a clear answer.


โœ๏ธ Building Dynamic Strings with Template Literals

Hardcoding strings is rarely practical. You often need to build them dynamically. Template literals make this clean and easy. You use backticks instead of quotes and embed variables with ${...}.

const blogURL: string = 'https://idavidov.eu/';

// Dynamically create a new URL
const newsletterURL: string = `${baseURL}newsletter`;

console.log(newsletterURL); // Outputs: 'https://idavidov.eu/newsletter'
Enter fullscreen mode Exit fullscreen mode

This is incredibly useful for QA work, such as building API endpoints with dynamic IDs or creating detailed assertion messages that include variable outputs.

โœจ The Special Trio: void, any, and unknown

Beyond the basics, TypeScript has special types for unique situations.

void: For Actions, Not Data

What about functions that do something but don't return a value? Think of a function that clicks an element. Its job is to perform an action, not to give you data back. This is what void is for.

// This helper performs a click but doesn't return anything.
function clickElement(selector: string): void {
  // In a real Playwright/Cypress test, you'd have:
  // await page.click(selector);
  console.log(`Successfully clicked on ${selector}!`);
}
Enter fullscreen mode Exit fullscreen mode

Using void makes your code clearer. It tells other developers (and your future self) that the function's purpose is its side effect, not its return value.

any: The Double-Edged Sword ๐Ÿ—ก๏ธ

Sometimes, you might be working with legacy JavaScript code or a poorly documented library. In these cases, you can use any as an "escape hatch." It effectively tells TypeScript, "Don't type-check this variable."

// Use with extreme caution!
let legacyData: any = { "user-id": 123, details: "some-info" };

// TypeScript won't complain about this, even if it's wrong.
console.log(legacyData.nonExistentProperty); // Returns 'undefined' at runtime
Enter fullscreen mode Exit fullscreen mode

The Risk: Using any completely defeats the purpose of TypeScript. It hides potential bugs and should be used as a last resort. Always aim to replace any with a proper type as soon as you can.

unknown: The Safe Alternative ๐Ÿ›ก๏ธ

So what if you truly don't know the type of data you're getting, like from an external API? Use unknown. It's the type-safe version of any.

unknown forces you to check the type of the data before you're allowed to do anything with it.

async function fetchUserData(userId: number): Promise<void> {
  const response = await fetch(`https://api.example.com/users/${userId}`);
  const data: unknown = await response.json();

  // We MUST check the type before using it
  if (
    typeof data === 'object' &&
    data !== null &&
    'name' in data &&
    typeof data.name === 'string'
  ) {
    // Only inside this block does TypeScript know data has a 'name' property
    console.log(`User's name is ${data.name.toUpperCase()}`);
  } else {
    console.error("API response is not in the expected format.");
  }
}
Enter fullscreen mode Exit fullscreen mode

unknown is perfect for QA because it forces us to write defensive code that can safely handle unexpected API responses without crashing.

๐Ÿš€ Your Next Step

We've covered the absolute essentials for getting started with TypeScript in a QA role. From basic types that clarify your intent to special types that help you handle tricky situations safely.

The single most important message is this: TypeScript isn't about adding complexity; it's about adding confidence. You can trust your tests more because an entire category of bugs is eliminated before you ever run them.

Confidence over Complexity

Your immediate next step? Go and convert one of your small JavaScript test files to TypeScript. Add types to your variables (.ts file extension) and see what potential issues you uncover. You might be surprised by what you find!


๐Ÿ™๐Ÿป Thank you for reading! Building robust, scalable automation frameworks is a journey best taken together. If you found this article helpful, consider joining a growing community of QA professionals ๐Ÿš€ who are passionate about mastering modern testing.

Join the community and get the latest articles and tips by signing up for the newsletter.

Top comments (0)