Transitioning to TypeScript: The Ultimate Starter Guide - Part 6

TypeScript from JavaScript Part 6 of 7: Generics and Utility Types

Hey there, wonderful developers! We're almost at the end of our journey from JavaScript to TypeScript. In this penultimate part of the series, we will explore the powerful features of generics and utility types in TypeScript.

As we always say, this series aims to demonstrate how TypeScript can simplify our work, save time, and elevate our apps. So, without further ado, let's dive into the world of generics and utility types!

1. Generics

Generics is a feature of TypeScript (and many other programming languages) that allows you to create reusable components that can work with different data types.

a. Generic Functions

Generic functions are functions that can work with any data type. You can create a generic function by using a type variable, which is a special kind of variable that works on types rather than values.

function identity<T>(arg: T): T {
    return arg;
}

let output1 = identity<string>("myString");
let output2 = identity<number>(100);

In this example, identity is a generic function that takes an argument arg of any type T and returns a value of the same type T. We can then call the identity function with different data types.

b. Generic Interfaces

Generic interfaces are interfaces that can work with any data type.

interface GenericIdentityFn {
    <T>(arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn = identity;

In this example, GenericIdentityFn is a generic interface that has a single method identity that can work with any data type.

c. Generic Classes

Generic classes are classes that can work with any data type.

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
    return x + y;
};

console.log(myGenericNumber.add(3, 4)); // 7

In this example, GenericNumber is a generic class that has a property zeroValue and a method add that can work with any data type.

2. Utility Types

Utility types are a set of generic types built into TypeScript that make it easy to transform types from one form to another. TypeScript provides several utility types, but we will cover the most commonly used ones here.

a. Partial

The Partial type takes a type T and makes all of its properties optional.

interface Todo {
    title: string;
    description: string;
}

function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
    return { ...todo, ...fieldsToUpdate };
}

const todo1 = { title: 'Learn TypeScript', description: 'Read TypeScript handbook' };
const todo2 = updateTodo(todo1, { description: 'Read TypeScript documentation' });

console.log(todo2); // { title: 'Learn TypeScript', description: 'Read TypeScript documentation' }

In this example, the updateTodo function takes a Todo object and a fieldsToUpdate object that has optional properties of the Todo type.

b. Readonly

The Readonly type takes a type T and makes all of its properties read-only.

interface Todo {
    title: string;
}

const todo: Readonly<Todo> = {
    title: 'Learn TypeScript',
};

todo.title = 'Learn JavaScript'; // Error: Cannot assign to 'title' because it is a read-only property

In this example, the todo object has a read-only title property, so it cannot be modified after it is created.

c. Record

The Record type creates a new type with properties of a given type.

interface PageInfo {
    title: string;
}

type Page = 'home' | 'about' | 'contact';

const nav: Record<Page, PageInfo> = {
    home: { title: 'Home' },
    about: { title: 'About' },
    contact: { title: 'Contact' },
};

console.log(nav.home.title); // Home

In this example, the nav object has properties home, about, and contact of the PageInfo type.

d. Pick

The Pick type creates a new type by picking a set of properties from an existing type.

interface Todo {
    title: string;
    description: string;
    completed: boolean;
}

type TodoPreview = Pick<Todo, 'title' | 'completed'>;

const todo: TodoPreview = {
    title: 'Learn TypeScript',
    completed: false,
};

console.log(todo); // { title: 'Learn TypeScript', completed: false }

In this example, the TodoPreview type has only the `title

andcompletedproperties of theTodo` type.

Conclusion

Generics and utility types are powerful features of TypeScript that allow you to create reusable components and transform types from one form to another. By using generics and utility types, you can make your code more flexible, reusable, and type-safe.

In the final part of this series, we will explore advanced topics like decorators and mixins. Stay tuned!


That’s a wrap. Thanks for reading.

If you're looking for more premium content and resources to help you start and grow your business, consider subscribing to my Newsletter.

Want to see what I am working on? Check out my Twitter

Did you find this article valuable?

Support Innovate Sphere by becoming a sponsor. Any amount is appreciated!