программирование programming ,

Generic тип данных Generic Types

Jan 29, 2023 · 14 мин. на прочтение 14 min read
Generic тип данных
Поделиться Share

Я долгое время не понимал, что такое Generic, для чего он нужен и как его использовать. А теперь я не понимаю, что там можно было не понимать.

Допустим мы создаём тип employee. У нас будет несколько полей: name типа string, age типа number и поле id, которое может принимать как тексовые значения, так и цифровые.

Вот один из вариантов написания такого типа

type emploee = {
  id: string | number
  name: string
  age: number
}

Второй вариант - это использовать generic тип и тогда мы можем сделать такую запись:

type emploee<T> = {
  id: T
  name: string
  age: number
}

Она более короткая. Особенно в тех случаях, когда у нас может быть не только string и number, но ещё и boolean и ещё какие-то типы. Чтобы их все не перечилсять, мы просто используем generic. В этом случае мы сможем определить тип поля id при объявлении переменной и присвоении ей типа emploee.

const user: emploee<number> = {
  id: 1,
  name: 'Vlad',
  age: 25,
}

В примере выше, тип type emploee<T>может принимать любой тип. Не только number или string. Но и null, undefined, boolean и так далее. Чтобы ограничить возможные варианты, мы можем использовать такую запись emploee<extends string | number>. В этом случае мы сможем присвоить полю id только string или number.

Ради прикола, я попросил chatGPT объяснить, что такое Generic простыми словами и написать статью для блога. Привожу её как есть. Нижеследующий текст - это просто Just For Fun. Моё первое знакомство с новыми технологиями.

Статья о Generic от chatGPT

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

Generics - это мощный инструмент в JavaScript, который позволяет нам описывать типы данных в нашем коде. Это делает наш код более гибким и легко используемым в различных ситуациях. Давайте рассмотрим простой пример. Возможно, вы хотите написать функцию, которая принимает два параметра и возвращает их сумму. Без использования Generics, ваш код может выглядеть так:

function sum(a, b) {
  return a + b;
}

console.log(sum(1, 2)); // 3
console.log(sum('Hello', ' World')); // 'Hello World'

Но если мы хотим использовать эту функцию для сложения только чисел, то в данном случае второй вызов функции вернет не ожидаемый результат, сложив строки. С использованием Generics, мы можем явно указать типы данных, которые мы ожидаем получить в качестве параметров:

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

console.log(sum<number>(1, 2)); // 3
console.log
(sum<string>('Hello', ' World')); // 'Hello World'

Как видно из примера, мы используем угловые скобки <> для обозначения типа Generics и задаем его имя (в данном случае T). Затем мы используем T в качестве типа данных для наших параметров и возвращаемого значения. При вызове функции мы можем явно указать тип данных, который мы ожидаем получить, используя то же имя (number или string в данном примере).

Generics также могут быть использованы для классов и интерфейсов. Например, мы можем создать класс “Queue”, который может быть использован для хранения очереди элементов любого типа:

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

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

  dequeue(): T | undefined {
    return this.items.shift();
  }
}

const numberQueue = new Queue<number>();
numberQueue.enqueue(1);
numberQueue.enqueue(2);
console.log(numberQueue.dequeue()); // 1
console.log(numberQueue.dequeue()); // 2

const stringQueue = new Queue<string>();
stringQueue.enqueue('Hello');
stringQueue.enqueue('World');
console.log(stringQueue.dequeue()); // 'Hello'
console.log(stringQueue.dequeue()); // 'World'

В общем, Generics - это мощный инструмент в JavaScript, который позволяет создавать функции, классы и интерфейсы, которые могут работать с различными типами данных. Это позволяет нам писать более гибкий и масштабируемый код, который может адаптироваться к различным потребностям и ситуациям.

Некоторые другие примеры использования Generics в JavaScript:

  • Создание функции для сортировки массивов различных типов (чисел, строк, объектов)
  • Создание функции для фильтрации массивов по различным критериям
  • Создание класса “Dictionary”, который может хранить пары ключ-значение любого типа

В целом, использование Generics может существенно улучшить читаемость, повторное использование и гибкость вашего кода. Если вы еще не использовали Generics в своем коде, стоит попробовать их использовать. Это может значительно упростить вашу работу и дать вам больше возможностей для решения сложных задач.

Ниже приведен простой пример создания функции сортировки с использованием Generics:

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

const numbers = [4, 1, 3, 2];
const sortedNumbers = sortArray(numbers);
console.log(sortedNumbers); // [1, 2, 3, 4]

const strings = ['d', 'c', 'b', 'a'];
const sortedStrings = sortArray(strings);
console.log(sortedStrings); // ['a', 'b', 'c', 'd']

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

В заключении, Generics - это мощный инструмент для разработки в JavaScript, который может значительно упростить и улучшить ваш код. Используйте их, когда вам нужно написать функцию, которая может работать с различными типами данных. Например, создание функции для клонирования объектов, которая может работать с объектами различных типов, или создание функции сортировки, которая может работать с массивами различных типов.

Однако, необходимо иметь в виду, что Generics также могут усложнять код и увеличивать его сложность, если их использование необоснованно. Поэтому, перед их использованием, рекомендуется хорошо обдумать и понять, насколько они нужны в конкретной ситуации. В общем, Generics - это мощный инструмент для разработки в JavaScript, который может значительно упростить и улучшить ваш код, но нужно использовать их с умом.

For a long time I didn’t understand what “Generic” is, why it’s needed, and how to use it. And now I don’t understand what there was to not understand.

Let’s say we create an employee type. It has a few fields: name of type string, age of type number, and an id field that can be either text or numeric.

One way to define such a type is:

type emploee = {
  id: string | number
  name: string
  age: number
}

Another way is to use a generic type, which allows a shorter definition:

type emploee<T> = {
  id: T
  name: string
  age: number
}

This is especially useful when id can be not only string and number, but also boolean and other types. Instead of listing all possible types, you use a generic. Then you can define the type of id when you declare a variable and assign it the emploee type.

const user: emploee<number> = {
  id: 1,
  name: 'Vlad',
  age: 25,
}

In the example above, type emploee<T> can accept any type — not only number or string, but also null, undefined, boolean, and so on. To limit possible variants, you can use something like emploee<extends string | number> so that id can be only string or number.

Just for fun, I asked chatGPT to explain what a Generic is in simple terms and write a blog post. Below is the text as-is (just for fun).

Generic article from chatGPT

Generic is a way to describe a data type in JavaScript that allows you to use the same code for different data types. This makes code more flexible and easier to use in different situations. For example, you can write a function that takes two parameters and returns their sum, and use it to add numbers or strings.

Generics are a powerful tool in JavaScript that allow us to describe data types in our code. This makes our code more flexible and easy to reuse in different situations.

Let’s look at a simple example. Maybe you want to write a function that takes two parameters and returns their sum. Without Generics, your code might look like this:

function sum(a, b) {
  return a + b;
}

console.log(sum(1, 2)); // 3
console.log(sum('Hello', ' World')); // 'Hello World'

But if we want to use this function only for adding numbers, the second call returns an unexpected result because it concatenates strings.

With Generics, we can explicitly specify the types we expect to receive as parameters:

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

console.log(sum<number>(1, 2)); // 3
console.log(sum<string>('Hello', ' World')); // 'Hello World'

As you can see, we use angle brackets <> to denote a generic type and give it a name (T in this case). Then we use T as the type for our parameters and return value. When calling the function, we can explicitly provide the type we expect using the same name (number or string in this example).

Generics can also be used for classes and interfaces. For example, we can create a Queue class that stores a queue of elements of any type:

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

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

  dequeue(): T | undefined {
    return this.items.shift();
  }
}

const numberQueue = new Queue<number>();
numberQueue.enqueue(1);
numberQueue.enqueue(2);
console.log(numberQueue.dequeue()); // 1
console.log(numberQueue.dequeue()); // 2

const stringQueue = new Queue<string>();
stringQueue.enqueue('Hello');
stringQueue.enqueue('World');
console.log(stringQueue.dequeue()); // 'Hello'
console.log(stringQueue.dequeue()); // 'World'

In general, Generics are a powerful tool that lets you create functions, classes, and interfaces that can work with different data types. This allows you to write more flexible and scalable code that can adapt to different needs and situations.

Some other examples of Generics usage:

  • A function to sort arrays of different types (numbers, strings, objects)
  • A function to filter arrays by different criteria
  • A Dictionary class that can store key-value pairs of any type

Overall, Generics can significantly improve readability, reuse, and flexibility of your code. If you haven’t used Generics yet, it’s worth trying — it can simplify your work and give you more options for solving complex tasks.

Below is a simple example of a generic sort function:

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

const numbers = [4, 1, 3, 2];
const sortedNumbers = sortArray(numbers);
console.log(sortedNumbers); // [1, 2, 3, 4]

const strings = ['d', 'c', 'b', 'a'];
const sortedStrings = sortArray(strings);
console.log(sortedStrings); // ['a', 'b', 'c', 'd']

In this example, sortArray uses a generic type T which allows it to work with arrays of any type. We can use it to sort number arrays and string arrays, and it will work for both.

In conclusion, Generics are a powerful tool in JavaScript development that can simplify and improve your code. Use them when you need a function that can work with different data types — for example, a cloning function for different objects, or a sorting function for arrays of different types.

However, keep in mind that Generics can also make code more complex when used without a good reason. So before using them, it’s worth thinking through whether you really need them in a given situation.

Generics are powerful — use them wisely.

Заходите в группу Telegram Join the Telegram group
Если есть вопросы или хотите пообщаться, то заходите в мою группу Telegram. If you have questions or want to chat, join my Telegram group.