📘 TypeScript

Sets (Set) in TypeScript 5 (Node.js): Complete Guide for Beginners

Множества (Set) в TypeScript

Представь, что у тебя есть коробка, в которую можно класть только уникальные предметы. Если ты попробуешь положить туда два одинаковых мячика, второй просто не поместится — он уже там есть! Именно так работает структура данных Set (Множество) в TypeScript.

Множество — это коллекция, которая хранит только уникальные значения. В отличие от массива, где элементы могут повторяться, в Set каждый элемент встречается только один раз. Это очень удобно, когда нужно, например, собрать список всех посетителей сайта без повторений или найти уникальные теги в статье.

Создание множества

Чтобы создать пустое множество, используй конструктор new Set(). Можно сразу передать массив с начальными значениями:

// Пустое множество
const emptySet = new Set<number>();

// Множество с начальными значениями
const fruits = new Set<string>(["яблоко", "банан", "апельсин"]);

// Множество с числами
const numbers = new Set<number>([1, 2, 3, 2, 1]); // Будет {1, 2, 3}

Основные операции с Set

Вот главные методы, которые нужно знать:

  • add(value) — добавляет элемент в множество. Если элемент уже есть, ничего не происходит.
  • delete(value) — удаляет элемент. Возвращает true, если элемент был удалён, и false, если его не было.
  • has(value) — проверяет, есть ли элемент в множестве. Возвращает true или false.
  • clear() — удаляет все элементы из множества.
  • size — свойство, показывающее количество элементов (не метод, а свойство!).
const colors = new Set<string>();

// Добавляем элементы
colors.add("красный");
colors.add("синий");
colors.add("зеленый");
colors.add("красный"); // Не добавится — уже есть!

console.log(colors.size); // 3

// Проверяем наличие
console.log(colors.has("синий")); // true
console.log(colors.has("желтый")); // false

// Удаляем элемент
colors.delete("зеленый");
console.log(colors.size); // 2

// Очищаем всё множество
colors.clear();
console.log(colors.size); // 0

Перебор элементов множества

Множество можно перебирать с помощью цикла for...of или метода forEach:

const animals = new Set<string>(["кот", "собака", "попугай"]);

// Способ 1: for...of
for (const animal of animals) {
  console.log(animal);
}

// Способ 2: forEach
animals.forEach((animal) => {
  console.log(animal);
});

Преобразование Set в массив и обратно

Очень часто нужно превратить множество в массив или наоборот. Для этого используй оператор ... (spread) или Array.from():

// Из Set в массив
const set = new Set<number>([1, 2, 3, 4, 5]);
const arr = [...set]; // [1, 2, 3, 4, 5]
// Или так: const arr = Array.from(set);

// Из массива в Set (убираем дубликаты)
const numbers = [1, 2, 2, 3, 3, 3, 4];
const uniqueNumbers = new Set<number>(numbers);
console.log([...uniqueNumbers]); // [1, 2, 3, 4]

Пример: программа для подсчёта уникальных слов

Давай напишем программу, которая читает строку текста и выводит количество уникальных слов в ней:

import * as readline from 'readline';

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.question('Введите текст: ', (text: string) => {
  // Разбиваем текст на слова (убираем знаки препинания)
  const words = text.toLowerCase().match(/[а-яёa-z]+/g) || [];
  
  // Создаём множество уникальных слов
  const uniqueWords = new Set<string>(words);
  
  console.log(`Всего слов: ${words.length}`);
  console.log(`Уникальных слов: ${uniqueWords.size}`);
  
  rl.close();
});

Типичные задачи с Set

Задача 1. Удаление дубликатов из массива

Самая популярная задача — убрать повторяющиеся элементы из массива:

function removeDuplicates<T>(arr: T[]): T[] {
  return [...new Set<T>(arr)];
}

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

Задача 2. Проверка пересечения двух множеств

Нужно найти общие элементы в двух коллекциях:

function findIntersection<T>(arr1: T[], arr2: T[]): T[] {
  const set1 = new Set<T>(arr1);
  const set2 = new Set<T>(arr2);
  const result: T[] = [];
  
  for (const item of set1) {
    if (set2.has(item)) {
      result.push(item);
    }
  }
  
  return result;
}

const group1 = ["Аня", "Боря", "Витя", "Галя"];
const group2 = ["Боря", "Галя", "Дима", "Ева"];
console.log(findIntersection(group1, group2)); // ["Боря", "Галя"]

Задача 3. Разность множеств

Найти элементы, которые есть в первом множестве, но нет во втором:

function findDifference<T>(arr1: T[], arr2: T[]): T[] {
  const set2 = new Set<T>(arr2);
  return arr1.filter(item => !set2.has(item));
}

const allStudents = ["Аня", "Боря", "Витя", "Галя", "Дима"];
const present = ["Аня", "Витя", "Дима"];
console.log(findDifference(allStudents, present)); // ["Боря", "Галя"]

Частые ошибки и как их избежать

Ошибка 1: Путать Set с Map

Set хранит только значения, а Map хранит пары ключ-значение. Не пытайся использовать Set как словарь!

// ❌ Неправильно
const badSet = new Set<string, number>(); // Ошибка! Set принимает только один тип

// ✅ Правильно
const goodSet = new Set<string>();

Ошибка 2: Думать, что Set сохраняет порядок

Set сохраняет порядок добавления элементов, но не сортирует их автоматически. Если нужна сортировка, преобразуй в массив:

const nums = new Set<number>([3, 1, 2]);
console.log([...nums]); // [3, 1, 2] — порядок добавления

// Если нужна сортировка:
const sorted = [...nums