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
and
completedproperties of the
Todo` 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