Introduction
In this chapter, we will explore generics in TypeScript. Generics allow you to write flexible, reusable functions and classes that can work with different types while maintaining type safety. Understanding how to use generics is essential for writing robust and reusable TypeScript code.
Table of Contents
- Definition
- Generic Functions
- Generic Classes
- Generic Interfaces
- Generic Constraints
- Using Multiple Type Variables
- Complete Example with Output
- Conclusion
Definition
Generics provide a way to create reusable components that can work with a variety of types instead of a single one. By using generics, you can create functions, classes, and interfaces that can operate with different data types while ensuring type safety.
Generic Functions
Definition
A generic function is a function that can operate on different types of data without sacrificing type safety. You define a generic function by adding a type parameter in angle brackets (<T>
) before the function's parameters.
Syntax
function functionName<T>(parameter: T): T {
// function implementation
}
Example
This example demonstrates a generic function that returns the input value.
function identity<T>(value: T): T {
return value;
}
console.log(identity<number>(42)); // Output: 42
console.log(identity<string>("Hello")); // Output: Hello
Output
42
Hello
Generic Classes
Definition
A generic class is a class that can operate on different types of data. You define a generic class by adding a type parameter in angle brackets (<T>
) after the class name.
Syntax
class ClassName<T> {
// class implementation
}
Example
This example demonstrates a generic class that stores a value and provides methods to get and set the value.
class Box<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
setValue(value: T): void {
this.value = value;
}
}
let numberBox = new Box<number>(123);
console.log(numberBox.getValue()); // Output: 123
let stringBox = new Box<string>("Hello");
console.log(stringBox.getValue()); // Output: Hello
Output
123
Hello
Generic Interfaces
Definition
A generic interface is an interface that can operate on different types of data. You define a generic interface by adding a type parameter in angle brackets (<T>
) after the interface name.
Syntax
interface InterfaceName<T> {
// interface implementation
}
Example
This example demonstrates a generic interface that defines a structure for storing a value and methods to get and set the value.
interface Container<T> {
getValue(): T;
setValue(value: T): void;
}
class GenericContainer<T> implements Container<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
setValue(value: T): void {
this.value = value;
}
}
let numberContainer = new GenericContainer<number>(456);
console.log(numberContainer.getValue()); // Output: 456
let stringContainer = new GenericContainer<string>("World");
console.log(stringContainer.getValue()); // Output: World
Output
456
World
Generic Constraints
Definition
Generic constraints allow you to restrict the types that can be used with a generic function, class, or interface. You define a generic constraint using the extends
keyword.
Syntax
function functionName<T extends Constraint>(parameter: T): T {
// function implementation
}
Example
This example demonstrates a generic function that works with objects that have a length
property.
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
console.log(logLength("Hello")); // Output: 5
console.log(logLength([1, 2, 3])); // Output: 3
// console.log(logLength(123)); // Error: Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.
Output
5
3
Using Multiple Type Variables
Definition
You can use multiple type variables in a generic function, class, or interface to work with multiple types simultaneously.
Syntax
function functionName<T, U>(param1: T, param2: U): void {
// function implementation
}
Example
This example demonstrates a generic function that works with two different types.
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
let result = pair<number, string>(123, "Hello");
console.log(result); // Output: [123, 'Hello']
Output
[123, 'Hello']
Complete Example with Output
In this section, we will combine the examples into a single TypeScript file, compile it to JavaScript, and run it to see the output.
TypeScript Code
You can test the following code in the TypeScript Playground:
// Generic Functions
function identity<T>(value: T): T {
return value;
}
console.log(identity<number>(42)); // Output: 42
console.log(identity<string>("Hello")); // Output: Hello
// Generic Classes
class Box<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
setValue(value: T): void {
this.value = value;
}
}
let numberBox = new Box<number>(123);
console.log(numberBox.getValue()); // Output: 123
let stringBox = new Box<string>("Hello");
console.log(stringBox.getValue()); // Output: Hello
// Generic Interfaces
interface Container<T> {
getValue(): T;
setValue(value: T): void;
}
class GenericContainer<T> implements Container<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
setValue(value: T): void {
this.value = value;
}
}
let numberContainer = new GenericContainer<number>(456);
console.log(numberContainer.getValue()); // Output: 456
let stringContainer = new GenericContainer<string>("World");
console.log(stringContainer.getValue()); // Output: World
// Generic Constraints
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
console.log(logLength("Hello")); // Output: 5
console.log(logLength([1, 2, 3])); // Output: 3
// console.log(logLength(123)); // Error: Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.
// Using Multiple Type Variables
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
let result = pair<number, string>(123, "Hello");
console.log(result); // Output: [123, 'Hello']
Conclusion
In this chapter, we covered generics in TypeScript, including generic functions, classes, and interfaces, as well as generic constraints and using multiple type variables. We provided a complete example with its output to illustrate how these concepts work in TypeScript. Understanding generics is essential for writing flexible and reusable TypeScript code that maintains type safety.
Comments
Post a Comment
Leave Comment