Декабрь в офисе не проходит без традиции тайного Санты. Мой вишлист остался пустым, но подарок, который я получила, удивил своей точностью. А вместе с ним пришло загадочное послание. Как новичку в компании, мне было трудно с первого взгляда угадать отправителя, поэтому я решила использовать TypeScript, чтобы найти своего Санту.

Подарок и сообщение ????

Вместе с подарком я получила тайное послание, которое стало отправной точкой типизации.

Загадочное послание от Тайного Санты
Загадочное послание от Тайного Санты

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

type HasSenseOfHumor = { hasSenseOfHumor: true };
type KnowsMyTaste = { knowsMyTaste: true };
type CanFindUniqueGifts = { canFindUniqueGifts: true };
type LeavesMysteriousMessages = { leavesMysteriousMessages: true };
type LovesCats = { lovesCats: true };
type UsesTripleEmoji = { usesTripleEmoji: true };

Изучение данных ????

В треде нашего корпоративного Slack я нашла имена всех участников и приуныла: никаких общих закономерностей, каждого можно описать только уникальным набором свойств. Конфиденциальность не позволяет мне раскрыть реальные имена, поэтому в роли примеров выступят Bob и Alice — условные Санты с характерными атрибутами.

type ParticipantA = {
  name: 'Alice';
  hasSenseOfHumor: true;
  knowsMyTaste: true;
  canFindUniqueGifts: true;
  leavesMysteriousMessages: false;
  usesTripleEmoji: false;
};
type ParticipantB = {
  name: 'Bob';
  hasSenseOfHumor: true;
  knowsMyTaste: true;
  canFindUniqueGifts: true;
  leavesMysteriousMessages: true;
  lovesCats: true;
  usesTripleEmoji: true;
};

Чтобы создать универсальный тип для всего списка, мне пришлось вручную назначить типы, соответствующие индивидуальности каждого участника, допуская, что у них могут быть и другие, ещё не известные мне характеристики.

type AllParticipants = ParticipantA | ParticipantB;

Фильтрация кандидатов ????

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

type FilteredParticipants = Extract<
  AllParticipants,
  HasSenseOfHumor & LeavesMysteriousMessages & UsesTripleEmoji
>;

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

type IsSingle<T, All = T> = T extends any
  ? Exclude<All, T> extends never
    ? T
    : never
  : never;

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

Разгадка ????

Силой типов и условных выражений я ограничила выбор до одного человека, который мог быть моим Тайным Сантой.

type SingleSecretSanta = IsSingle<FilteredParticipants>

Осталось только навести курсор на type SecretSanta и позволить TypeScript подсказать мне, кто же скрывается за этой загадкой.

type SecretSanta = SingleSecretSanta extends never
  ? 'No single match found'
  : SingleSecretSanta;

Узнать итог моего поиска можно здесь — код доступен в TypeScript Playground.

Комментарии (1)


  1. AstorS1
    10.01.2024 18:39

    Тоже хочу узнать своего тайного Санту. Подарок достаточно дорогой (в 6 раз выше обсуждённого комфортного лимита) , но очень в тему! И мне бы хотелось приватно компенсировать часть затрат.

    Но мне проще, к подарку было приложено рукописное письмо. Не знаю, сам ли Санта его писал или его помощники. Правда дело осложняется тем, что мы в разных локация, 250+ участников.