Exploring Advanced TypeScript Concepts: A Deep Dive with Examples

Sumeet Panchal
4 min readSep 6, 2023

TypeScript, a superset of JavaScript, adds a robust layer of static typing to the language, enhancing code quality and developer productivity. While TypeScript’s basic features are widely used, there are some advanced concepts that can take your TypeScript skills to the next level. In this blog post, we’ll explore several advanced TypeScript concepts in detail, with short examples to help you understand their practical applications.

1. Type Aliases:

Type aliases allow you to create custom, reusable types. They’re handy for simplifying complex type definitions and improving code readability.

Type aliases can simplify complex type definitions and improve code readability. Let’s create a more intricate example:

type Employee = {
id: number;
name: string;
jobTitle: string;
};

type Department = {
id: number;
name: string;
manager: Employee;
};

const hrManager: Employee = {
id: 1,
name: "Alice",
jobTitle: "HR Manager",
};

const hrDepartment: Department = {
id: 101,
name: "HR Department",
manager: hrManager,
};

Here, we’ve used type aliases to define Employee and Department types, making it easier to represent the structure of these entities.

2. Unions and Intersections:

Unions (|) and intersections (&) are powerful tools for defining flexible types.

Let’s explore unions and intersections with more complex scenarios:

Unions:

type Vehicle = "Car" | "Bicycle" | "Motorcycle";

function getVehicleDescription(vehicle: Vehicle): string {
switch (vehicle) {
case "Car":
return "Four-wheeled vehicle";
case "Bicycle":
return "Two-wheeled, human-powered vehicle";
case "Motorcycle":
return "Two-wheeled motorized vehicle";
default:
return "Unknown vehicle type";
}
}

Here, the Vehicle type is a union of different vehicle types, allowing us to create a function that handles multiple vehicle options.

Intersections:

type Employee = {
id: number;
name: string;
};

type Role = {
role: string;
};

type Developer = Employee & Role;

const softwareEngineer: Developer = {
id: 1,
name: "John Doe",
role: "Software Engineer",
};

In this example, we’ve defined two types, Employee and Role, and then used an intersection to create a Developer type that combines both Employee and Role properties. This represents a developer's identity and role in the organization.

3. Literal Types:

Literal types allow you to specify exact values a variable can hold.

Let’s expand on literal types by creating a function that uses them:

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

function sendRequest(url: string, method: HttpMethod): void {
// Send an HTTP request using the specified method
}

sendRequest("/api/data", "POST"); // This is valid
sendRequest("/api/data", "PATCH"); // Error: Argument of type '"PATCH"' is not assignable to parameter of type 'HttpMethod'.

Here, HttpMethod is a literal type that specifies valid HTTP methods. The sendRequest function ensures that only valid methods can be used.

4. Type Narrowing:

Type narrowing involves refining a variable’s type based on runtime checks.

Let’s create a more detailed type-narrowing example using a function:

type Pet = { name: string; kind: "dog" | "cat" };

function printPet(pet: Pet) {
if (pet.kind === "dog") {
console.log(`Name: ${pet.name}, Kind: Dog`);
} else if (pet.kind === "cat") {
console.log(`Name: ${pet.name}, Kind: Cat`);
} else {
console.log(`Unknown pet kind`);
}
}

const myDog: Pet = { name: "Buddy", kind: "dog" };
printPet(myDog);

In this enhanced example, we’ve added an “Unknown pet kind” case, demonstrating more precise type narrowing based on the pet.kind property.

5. Nullable Type:

The null and undefined values are part of every type by default. But sometimes, you want to express that a variable can be explicitly null or undefined. TypeScript provides the null and undefined types for this purpose.

Let’s explore nullable types with a function that may return null:

function findUserById(id: number): User | null {
// Search for a user by ID and return it if found; otherwise, return null
}

const user = findUserById(123);

if (user !== null) {
console.log(`User found: ${user.name}`);
} else {
console.log("User not found");
}

Here, the findUserById a function can return either a User or null, and we handle both cases accordingly.

6. The unknown Type:

The unknown type is a type-safe counterpart to any. It forces you to perform type checks before accessing its properties.

Consider a scenario where you receive data of unknown types from an API:

let userInput: unknown;

if (typeof userInput === "string") {
console.log(userInput.toUpperCase());
} else {
console.log("User input is not a string");
}

By using the unknown type, we ensure type safety by checking the type of userInput before attempting to perform operations on it.

7. The never Type:

The never type represents values that never occur, often used for functions that never return or throw errors.

Here’s a more intricate example demonstrating the never type with a custom error handler:

function throwError(message: string): never {
throw new Error(message);
}

function handleError(error: unknown): void {
if (error instanceof Error) {
console.error(`Error: ${error.message}`);
} else {
const errorMsg = "An unknown error occurred.";
console.error(errorMsg);
throwError(errorMsg);
}
}

try {
// Simulate an error
handleError("This is an error");
} catch (e) {
console.log("Caught an error:", e.message);
}

In this example, the handleError function handles both known errors (instances of Error) and unknown errors, using the never type to ensure that the program does not continue after an unknown error occurs.

These advanced TypeScript concepts can significantly improve your code’s safety and expressiveness. By mastering type aliases, unions, intersections, literal types, type narrowing, nullable types, unknown, and never, you'll be better equipped to write robust and maintainable TypeScript code. Start incorporating these concepts into your projects to take full advantage of TypeScript's capabilities and elevate your development skills to new heights.

--

--