Generics in TypeScript

Generics in TypeScript

If you’re just starting out with TypeScript, you may have heard the term “Generics” but are unsure what they mean. Simply put, Generics enable you to write code that works with different data types, making your code more versatile and flexible. Although it can be confusing to grasp the concept at first, once you understand Generics, they can save you a lot of time and effort when writing code.

Syntax for TypeScript Generics

In TypeScript, Generics use angle brackets (<>)to define a placeholder type that can be applied to functions, classes, and interfaces. For instance, you can create a function that adds two numbers and concatenates two strings using the same code. Here’s an example of a generic function that adds two numbers:

function add<T>(a: T, b: T): T {
return a + b;
}

In this example, T is a placeholder type that can be replaced with any data type. The function takes two arguments of type T, adds them together, and returns the result as type T. Here’s how you can call the function with different data types:

const sum1 = add<number>(2, 3); // returns 5
const sum2 = add<string>('Rabi', ' Siddique'); // returns 'Rabi Siddique'

In the first example, number is passed as the generic type parameter T, and the function returns a number. In the second example, string is passed as the generic type parameter T, and the function returns a string.

Why Use TypeScript Generics?

Let’s say you’re writing a function that sorts an array of numbers. You might write something like this:

function sortNumbers(arr: number[]): number[] {
// ... sorting logic ...
return arr;
}

This function takes an array of numbers as an argument and returns a sorted array of numbers. But what if you want to sort an array of strings? You’d have to write a separate function for that:

function sortStrings(arr: string[]): string[] {
// ... sorting logic ...
return arr;
}

This quickly becomes tedious, especially when working with many different data types. This is where TypeScript Generics come in. With Generics, you can write a single function that works with any data type. Here’s an example:

function sortArray<T>(arr: T[]): T[] {
// ... sorting logic ...
return arr;
}

So, if you call this function with an array of numbers like this:

sortArray<number>([3, 1, 4, 1, 5]);
sortArray<string>(["banana", "apple", "pear", "orange"]);

In the first example, number is passed as the generic type parameter T, and the function sorts the array accordingly. In the second example, string is passed as the generic type parameter T, and the function sorts the array of strings.

In this example, TypeScript Generics made your code more adaptable to changing requirements, as you can simply swap out the data type without having to rewrite the entire code.

Using TypeScript Generics with Classes

TypeScript Generics can also be used with classes to create reusable classes that can work with different types. To use Generics with a class, you can define a type parameter inside angle brackets <> after the class name. This creates a placeholder for the data type the class will work with. Here’s an example of how to define a generic class using TypeScript Generics:

class List<T> {
private items: T[] = [];

add(item: T) {
this.items.push(item);
}

getItems(): T[] {
return this.items;
}
}

In this code, the type parameter T represents the type of items in the List. The List class has two methods, add and getItems. The add method takes an item of type T as an argument and adds it to the items array. The getItems method returns the items array.

To use this generic class, simply specify the actual type of the data as an argument. Here’s an example of how to use the List class:

const numbers = new List<number>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
console.log(numbers.getItems()); // [1, 2, 3]

const strings = new List<string>();
strings.add("Rabi");
strings.add("Siddique");
console.log(strings.getItems()); // ["Rabi", "Siddique"]

In this code, we create two instances of the List class, one for numbers and one for strings. By using the type parameter T to specify the actual type of the data for each instance of the List class, we can reuse the same class for different data types without writing separate implementations for each data type.

Using TypeScript Generics with Interfaces

If you are using TypeScript, you can use Generics with Interfaces to create reusable interfaces that can work with different types. The type parameter acts as a placeholder for the actual type that will be used with the interface. Here’s an example of how to define a generic interface:

interface Box<T> {
value: T;
}

In this example, the Box interface has a generic type parameter T. The value property of the Boxinterface is of type T, which means that it can hold any value of any type.

To use this interface, you can specify the actual type of data as an argument. Here is an example of how to use the Boxinterface:

const stringBox: Box<string> = { value: 'Rabi Siddique' };
const numberBox: Box<number> = { value: 27 };

In this code, we create two instances of the Boxinterface, one for strings and one for numbers.

You can also use the generic type parameter to create interfaces with multiple properties of the same type. Here’s an example:

interface Pair<T> {
first: T;
second: T;
}

In this example, the Pair interface has the type parameter T. The first and second properties of the Pair interface are both of type T, which means that they can hold any value of the same type. When you create a Pair object, you can specify the type that will be used with the interface:

const stringPair: Pair<string> = { first: 'Rabi', second: 'Siddique' };
const numberPair: Pair<number> = { first: 27, second: 24 };

TypeScript Generics Constraints

TypeScript Generics Constraints allow you to specify the type or set of types that a type parameter can accept. This is done by using the extends keyword to specify the constraint. For example, let’s define a generic function that accepts only strings and numbers and prints their value:

function printValue<T extends number|string>(arg: T): void {
console.log(arg)
}

In this example, we usethe extends keyword to restrict the type parameter T to only number or string types. This means that any other data type passed as an argument to this function will result in a compiler error.

printValue("Rabi Siddique") // Rabi Siddique
printValue(24) // 24
printValue(true) // Compiler error: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.

Now let’s see another example. Suppose you have an object interface named Person with two properties, name and age. You want to create a function that takes an object of type Person, and logs their name and age to the console. However, you want to make sure that the function only accepts objects with the name and age properties, and not any other properties. Here is how you can achieve this:

interface Person {
name: string;
age: number;
}

function logPerson<T extends Person>(person: T): void {
console.log(`Name: ${person.name}, Age: ${person.age}`);
}

In this code, we added a constraint to the type parameter T by using the extends keyword, followed by the type or interface we want to restrict T to. Here, we have restricted T to objects with the same properties as the Person interface. Here, we have restricted T to objects with the same properties as the Person interface.

You can now use this function with an object that conforms to the Person interface, like this:

const person: Person = {
name: "Rabi Siddique",
age: 25
};

logPerson(person); // "Name: Rabi Siddique, Age: 25"

Conclusion

TypeScript Generics is a powerful feature that allows you to write reusable and flexible code. Generics enable you to create functions, classes, and interfaces that can work with different data types without writing separate implementations for each data type. By using TypeScript Generics, you can make your code more scalable and maintainable while ensuring type safety.

Thank you for reading. I hope this post is helpful to you. If you have any further questions, don’t hesitate to reach out. I’m always happy to help.

Let’s connect:
LinkedIn
Twitter

Level Up Coding

Thanks for being a part of our community! Before you go:

🚀👉 Join the Level Up talent collective and find an amazing job


Generics in TypeScript was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Rabi Siddique

Generics in TypeScript

If you’re just starting out with TypeScript, you may have heard the term “Generics” but are unsure what they mean. Simply put, Generics enable you to write code that works with different data types, making your code more versatile and flexible. Although it can be confusing to grasp the concept at first, once you understand Generics, they can save you a lot of time and effort when writing code.

Syntax for TypeScript Generics

In TypeScript, Generics use angle brackets (<>)to define a placeholder type that can be applied to functions, classes, and interfaces. For instance, you can create a function that adds two numbers and concatenates two strings using the same code. Here’s an example of a generic function that adds two numbers:

function add<T>(a: T, b: T): T {
return a + b;
}

In this example, T is a placeholder type that can be replaced with any data type. The function takes two arguments of type T, adds them together, and returns the result as type T. Here's how you can call the function with different data types:

const sum1 = add<number>(2, 3); // returns 5
const sum2 = add<string>('Rabi', ' Siddique'); // returns 'Rabi Siddique'

In the first example, number is passed as the generic type parameter T, and the function returns a number. In the second example, string is passed as the generic type parameter T, and the function returns a string.

Why Use TypeScript Generics?

Let’s say you’re writing a function that sorts an array of numbers. You might write something like this:

function sortNumbers(arr: number[]): number[] {
// ... sorting logic ...
return arr;
}

This function takes an array of numbers as an argument and returns a sorted array of numbers. But what if you want to sort an array of strings? You’d have to write a separate function for that:

function sortStrings(arr: string[]): string[] {
// ... sorting logic ...
return arr;
}

This quickly becomes tedious, especially when working with many different data types. This is where TypeScript Generics come in. With Generics, you can write a single function that works with any data type. Here’s an example:

function sortArray<T>(arr: T[]): T[] {
// ... sorting logic ...
return arr;
}

So, if you call this function with an array of numbers like this:

sortArray<number>([3, 1, 4, 1, 5]);
sortArray<string>(["banana", "apple", "pear", "orange"]);

In the first example, number is passed as the generic type parameter T, and the function sorts the array accordingly. In the second example, string is passed as the generic type parameter T, and the function sorts the array of strings.

In this example, TypeScript Generics made your code more adaptable to changing requirements, as you can simply swap out the data type without having to rewrite the entire code.

Using TypeScript Generics with Classes

TypeScript Generics can also be used with classes to create reusable classes that can work with different types. To use Generics with a class, you can define a type parameter inside angle brackets <> after the class name. This creates a placeholder for the data type the class will work with. Here’s an example of how to define a generic class using TypeScript Generics:

class List<T> {
private items: T[] = [];

add(item: T) {
this.items.push(item);
}

getItems(): T[] {
return this.items;
}
}

In this code, the type parameter T represents the type of items in the List. The List class has two methods, add and getItems. The add method takes an item of type T as an argument and adds it to the items array. The getItems method returns the items array.

To use this generic class, simply specify the actual type of the data as an argument. Here’s an example of how to use the List class:

const numbers = new List<number>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
console.log(numbers.getItems()); // [1, 2, 3]

const strings = new List<string>();
strings.add("Rabi");
strings.add("Siddique");
console.log(strings.getItems()); // ["Rabi", "Siddique"]

In this code, we create two instances of the List class, one for numbers and one for strings. By using the type parameter T to specify the actual type of the data for each instance of the List class, we can reuse the same class for different data types without writing separate implementations for each data type.

Using TypeScript Generics with Interfaces

If you are using TypeScript, you can use Generics with Interfaces to create reusable interfaces that can work with different types. The type parameter acts as a placeholder for the actual type that will be used with the interface. Here’s an example of how to define a generic interface:

interface Box<T> {
value: T;
}

In this example, the Box interface has a generic type parameter T. The value property of the Boxinterface is of type T, which means that it can hold any value of any type.

To use this interface, you can specify the actual type of data as an argument. Here is an example of how to use the Boxinterface:

const stringBox: Box<string> = { value: 'Rabi Siddique' };
const numberBox: Box<number> = { value: 27 };

In this code, we create two instances of the Boxinterface, one for strings and one for numbers.

You can also use the generic type parameter to create interfaces with multiple properties of the same type. Here’s an example:

interface Pair<T> {
first: T;
second: T;
}

In this example, the Pair interface has the type parameter T. The first and second properties of the Pair interface are both of type T, which means that they can hold any value of the same type. When you create a Pair object, you can specify the type that will be used with the interface:

const stringPair: Pair<string> = { first: 'Rabi', second: 'Siddique' };
const numberPair: Pair<number> = { first: 27, second: 24 };

TypeScript Generics Constraints

TypeScript Generics Constraints allow you to specify the type or set of types that a type parameter can accept. This is done by using the extends keyword to specify the constraint. For example, let’s define a generic function that accepts only strings and numbers and prints their value:

function printValue<T extends number|string>(arg: T): void {
console.log(arg)
}

In this example, we usethe extends keyword to restrict the type parameter T to only number or string types. This means that any other data type passed as an argument to this function will result in a compiler error.

printValue("Rabi Siddique") // Rabi Siddique
printValue(24) // 24
printValue(true) // Compiler error: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.

Now let’s see another example. Suppose you have an object interface named Person with two properties, name and age. You want to create a function that takes an object of type Person, and logs their name and age to the console. However, you want to make sure that the function only accepts objects with the name and age properties, and not any other properties. Here is how you can achieve this:

interface Person {
name: string;
age: number;
}

function logPerson<T extends Person>(person: T): void {
console.log(`Name: ${person.name}, Age: ${person.age}`);
}

In this code, we added a constraint to the type parameter T by using the extends keyword, followed by the type or interface we want to restrict T to. Here, we have restricted T to objects with the same properties as the Person interface. Here, we have restricted T to objects with the same properties as the Person interface.

You can now use this function with an object that conforms to the Person interface, like this:

const person: Person = {
name: "Rabi Siddique",
age: 25
};

logPerson(person); // "Name: Rabi Siddique, Age: 25"

Conclusion

TypeScript Generics is a powerful feature that allows you to write reusable and flexible code. Generics enable you to create functions, classes, and interfaces that can work with different data types without writing separate implementations for each data type. By using TypeScript Generics, you can make your code more scalable and maintainable while ensuring type safety.

Thank you for reading. I hope this post is helpful to you. If you have any further questions, don’t hesitate to reach out. I’m always happy to help.

Let’s connect:
LinkedIn
Twitter

Level Up Coding

Thanks for being a part of our community! Before you go:

🚀👉 Join the Level Up talent collective and find an amazing job


Generics in TypeScript was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Rabi Siddique


Print Share Comment Cite Upload Translate Updates
APA

Rabi Siddique | Sciencx (2023-04-10T00:44:41+00:00) Generics in TypeScript. Retrieved from https://www.scien.cx/2023/04/10/generics-in-typescript-2/

MLA
" » Generics in TypeScript." Rabi Siddique | Sciencx - Monday April 10, 2023, https://www.scien.cx/2023/04/10/generics-in-typescript-2/
HARVARD
Rabi Siddique | Sciencx Monday April 10, 2023 » Generics in TypeScript., viewed ,<https://www.scien.cx/2023/04/10/generics-in-typescript-2/>
VANCOUVER
Rabi Siddique | Sciencx - » Generics in TypeScript. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/04/10/generics-in-typescript-2/
CHICAGO
" » Generics in TypeScript." Rabi Siddique | Sciencx - Accessed . https://www.scien.cx/2023/04/10/generics-in-typescript-2/
IEEE
" » Generics in TypeScript." Rabi Siddique | Sciencx [Online]. Available: https://www.scien.cx/2023/04/10/generics-in-typescript-2/. [Accessed: ]
rf:citation
» Generics in TypeScript | Rabi Siddique | Sciencx | https://www.scien.cx/2023/04/10/generics-in-typescript-2/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.