Обобщения в TypeScript

Обобщения в TypeScript

В этой статье объясняются обобщения в TypeScript.

YouTube Video

Обобщения в TypeScript

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

Основы обобщений

Обобщения работают как шаблоны, принимающие типы в качестве аргументов, что позволяет функциям и классам обрабатывать разные типы.

Обобщенные функции

Ниже приведен пример функции с типами её аргументов, заданными с использованием обобщений.

1function identity<T>(value: T): T {
2    return value;
3}
4
5console.log(identity<number>(42));       // 42
6console.log(identity<string>("Hello"));  // Hello
  • T — это параметр типа, который представляет типы аргументов функции и её возвращаемого значения. Фактический тип определяется при вызове функции.
  • Указывая явно <number> или <string>, вы задаёте тип.

Обобщенные типы работают и без явного указания, так как TypeScript выполняет вывод типов.

1function identity<T>(value: T): T {
2    return value;
3}
4
5console.log(identity(42));       // 42
6console.log(identity("Hello"));  // Hello

Ограничения для обобщений

Добавляя ограничения для обобщений, вы можете ограничить их приём только определённых типов.

1function loggingIdentity<T extends { length: number }>(arg: T): T {
2    console.log(arg.length);
3    return arg;
4}
5
6loggingIdentity("Hello");  // 5
7loggingIdentity([1, 2, 3]);  // 3
8
9// loggingIdentity(42);  // Error: number does not have a length property.
  • Указание T extends { length: number } означает, что T должен быть типом, содержащим свойство length. Следовательно, типы без свойства length не будут приниматься.

Обобщенные классы

Классы также можно определять, используя обобщения. Обобщенные классы предоставляют гибкие типы для свойств и методов.

 1class Box<T> {
 2    private _value: T;
 3
 4    constructor(value: T) {
 5        this._value = value;
 6    }
 7
 8    public getValue(): T {
 9        return this._value;
10    }
11
12    public setValue(value: T): void {
13        this._value = value;
14    }
15}
16
17const numberBox = new Box<number>(100);
18console.log(numberBox.getValue());  // 100
19
20const stringBox = new Box<string>("Hello");
21console.log(stringBox.getValue());  // Hello
  • Box<T> объявляет тип T, используемый внутри класса, в качестве обобщения. Это позволяет переиспользовать тот же класс для различных типов.

Обобщенные интерфейсы

Обобщения также можно использовать с интерфейсами.

 1interface Pair<T, U> {
 2    first: T;
 3    second: U;
 4}
 5
 6const numberStringPair: Pair<number, string> = { first: 1, second: "One" };
 7console.log(numberStringPair);  // { first: 1, second: 'One' }
 8
 9const booleanArrayPair: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
10console.log(booleanArrayPair);  // { first: true, second: [ 1, 2, 3 ] }
  • Указав два обобщенных типа с помощью Pair<T, U>, вы можете определить объект с комбинацией различных типов.

Аргументы типов по умолчанию

Также можно задать тип по умолчанию для параметров обобщённого типа.

1function createArray<T = string>(length: number, value: T): T[] {
2    return Array(length).fill(value);
3}
4
5console.log(createArray(3, "a"));   // ['a', 'a', 'a']
6console.log(createArray(3, 100));   // [100, 100, 100]
  • Мы устанавливаем аргумент типа по умолчанию как string с помощью <T = string>. Если тип не указан явно, T будет иметь тип string.

Обобщённые псевдонимы типов

Обобщённые типы также могут использоваться в качестве псевдонимов типов (type).

 1type Result<T> = {
 2    success: boolean;
 3    data: T;
 4};
 5
 6const successResult: Result<number> = { success: true, data: 42 };
 7const errorResult: Result<string> = { success: false, data: "Error occurred" };
 8
 9console.log(successResult);  // { success: true, data: 42 }
10console.log(errorResult);    // { success: false, data: 'Error occurred' }
  • Result<T> представляет объект результата, содержащий данные типа T. Таким образом, вы можете создавать гибкие псевдонимы типов, используя обобщения.

Несколько обобщённых типов

Используя несколько обобщённых типов, вы можете определить ещё более универсальные функции и классы.

1function merge<T, U>(obj1: T, obj2: U): T & U {
2    return { ...obj1, ...obj2 };
3}
4
5const person = { name: "Alice" };
6const job = { title: "Engineer" };
7
8const merged = merge(person, job);
9console.log(merged);  // { name: 'Alice', title: 'Engineer' }
  • Функция merge принимает два разных типа T и U и объединяет их, возвращая новый объект.

Резюме

  • Обобщения позволяют создавать многократно используемый и типобезопасный код, рассматривая типы как параметры.
  • Используя обобщения в функциях, классах и интерфейсах, вы можете писать гибкую логику, работающую с различными типами.
  • Добавляя ограничения к параметрам типов или задавая аргументы типов по умолчанию, вы можете контролировать область использования обобщений.

Используя обобщения, вы можете писать независимый от типов, универсальный код, максимально используя мощную систему типов TypeScript.

Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.

YouTube Video