Hack Frontend Community

What is Generic in TypeScript

Generic in TypeScript is the ability to create universal components and functions that can work with any data types while maintaining type safety. Using Generic you can create functions, classes and interfaces that can work with different types without losing strict typing.

Why Generics?

  1. Flexibility: Generics allow creating universal functions and classes that can work with various data types. This allows avoiding code duplication while ensuring type safety.

  2. Code reuse: Generics allow writing code that can be reused for different types, improving readability and reducing repetition.

  3. Type safety: Using Generics provides type checking at compile time, helping avoid errors related to incorrect type usage.

Generics in functions

Using Generic you can create functions that accept parameters of different types, while TypeScript will track data types.

Example:

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

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

In this example T is a generic type that will be automatically determined based on the passed argument type. The identity function returns a value of the same type as the passed argument.

Generics with arrays

We can create functions for working with arrays where array elements can be of any type.

function logArray<T>(arr: T[]): void {
  arr.forEach(item => console.log(item));
}

logArray([1, 2, 3]);  // number[]
logArray(["a", "b", "c"]);  // string[]

In this example the logArray function accepts an array with any data types and outputs its elements to console.

Generics in interfaces

Generics can be used in interfaces to create more flexible and universal data structures.

interface Box<T> {
  value: T;
}

let box1: Box<string> = { value: "Hello" };
let box2: Box<number> = { value: 100 };

In this example Box is a universal interface that can work with any types, and the data type will be set when creating an interface instance.

Generics in classes

Generics can also be used in classes to create universal classes.

class Box<T> {
  private value: T;

  constructor(value: T) {
    this.value = value;
  }

  getValue(): T {
    return this.value;
  }
}

const box1 = new Box<string>("Hello");
const box2 = new Box<number>(100);

console.log(box1.getValue());  // "Hello"
console.log(box2.getValue());  // 100

In this example the Box class uses Generic to work with different data types, allowing creating instances with different value types.

Generic constraints

You can restrict types that can be used in Generic using constraints. For example, you can specify that a type parameter must be an object with a specific property.

function logLength<T extends { length: number }>(arg: T): void {
  console.log(arg.length);
}

logLength("Hello");  // 5
logLength([1, 2, 3]);  // 3

Here T extends { length: number } indicates that T must be an object with a length property, thus the function can only work with types like strings or arrays.