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