Taming TypeScript

The TypeScript Tutorial for The Hater

Functions That Don't Lie

What does this function even do?

In JavaScript, you've probably seen or written functions like this:

function calculateTotal(items, options) {
  // ... what is `items`? An array of numbers? An array of objects?
  // ... what is `options`? An object? What are its properties?
  // ... what does this function return? A number? A string?
}

To use this function correctly, you have to read its source code, find where it's used elsewhere, or hope there's good documentation. TypeScript eliminates this guesswork by allowing you to type a function's inputs (parameters) and output (return value).

A well-typed function is like a contract. It clearly states what it needs and what it will provide.

Typing Function Parameters

You can add type annotations to function parameters, just like with variables.

function greet(name: string) { ... }

This tells TypeScript that the greet function must be called with one argument, and that argument must be a string.

Exercise 1: Catching Incorrect Arguments

  1. The printUser function below expects a name (string) and an age (number).
  2. Someone has tried to call it with the arguments in the wrong order.
  3. Hover over the error to see TypeScript explain the problem.
  4. Fix the function call so that the types of the arguments match the types of the parameters.
Interactive Editor
Loading...

Typing Return Values

You can also explicitly type what a function returns. The syntax goes after the parameter list.

function getGreeting(name: string): string { ... }

This function now has a contract: "You must give me a string, and I promise I will give you a string back."

Often, TypeScript can infer the return type just by looking at your return statements. However, being explicit makes your code clearer and ensures the function actually returns what you think it does.

Exercise 2: A Lying Function

  1. The calculatePriceWithTax function says it will return a number.
  2. However, inside the function, a bug is causing it to return a formatted string.
  3. TypeScript spots this lie immediately. Hover over the error on the function declaration to see it.
  4. Fix the function's logic so that it correctly returns a number.
Interactive Editor
Loading...
Click to see the solution
function calculatePriceWithTax(price: number): number {
  const tax = price * 0.22;
  
  // ✅ Correct!
  return price + tax;
}

Building a Complete, Type-Safe Function

Let's combine everything we've learned: type aliases, typed arrays, and typed functions. This is the bread and butter of writing type-safe code.

Exercise 3: The User Processor

  1. We have a User type, an array of users, and a function getUserNames.
  2. The function should take an array of User objects and return an array of their names (string[]).
  3. Add the correct type annotations to the function's parameter and its return value.
  4. Complete the function logic.
Interactive Editor
Loading...
Click to see the solution
type User = { id: number; name: string; };
const users: User[] = [{ id: 1, name: "Luigi" }, { id: 2, name: "Mario" }];

function getUserNames(users: User[]): string[] {
  return users.map(user => user.name);
}

const userNames = getUserNames(users);
console.log(userNames);

By explicitly typing the inputs and outputs, your function becomes a reliable, self-documenting building block in your application.