Весной стартует сезон найма, успей отхватить свой оффер!

Что такое Generic в TypeScript

Generic в TypeScript — это возможность создавать универсальные компоненты и функции, которые могут работать с любыми типами данных, при этом сохраняют типовую безопасность. С помощью Generic можно создать функции, классы и интерфейсы, которые могут работать с разными типами, не теряя при этом строгой типизации.

Зачем нужны Generic?

  1. Гибкость: Generic позволяют создавать универсальные функции и классы, которые могут работать с различными типами данных. Это дает возможность избежать дублирования кода, обеспечивая при этом типовую безопасность.

  2. Повторное использование кода: Generic позволяют писать код, который можно многократно использовать для разных типов, улучшая читаемость и уменьшая количество повторений.

  3. Типовая безопасность: Использование Generic обеспечивает проверку типов в момент компиляции, что помогает избежать ошибок, связанных с неправильным использованием типов.

Generic в функциях

С помощью Generic можно создавать функции, которые принимают параметры разных типов, при этом TypeScript будет отслеживать типы данных.

Пример:

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

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

В этом примере T — это обобщенный тип, который будет автоматически определяться на основе типа переданного аргумента. Функция identity возвращает значение того же типа, что и переданному аргументу.

Generic с массивами

Мы можем создавать функции для работы с массивами, где элементы массива могут быть любого типа.

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

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

В этом примере функция logArray принимает массив с любыми типами данных и выводит его элементы в консоль.

Generic в интерфейсах

Generic могут быть использованы в интерфейсах для создания более гибких и универсальных структур данных.

interface Box<T> {
  value: T;
}

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

В этом примере Box является универсальным интерфейсом, который может работать с любыми типами, и тип данных будет задаваться при создании экземпляра интерфейса.

Generic в классах

Generic также можно использовать в классах для создания универсальных классов.

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

В этом примере класс Box использует Generic для работы с разными типами данных, что позволяет создавать экземпляры с различными типами значений.

Ограничения Generic

Можно ограничить типы, которые могут быть использованы в Generic, с помощью ограничений. Например, вы можете указать, что параметр типа должен быть объектом с определенным свойством.

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

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

Здесь T extends { length: number } указывает, что T должен быть объектом с свойством length, таким образом, функция может работать только с такими типами, как строками или массивами.