Паттерн Discriminated Union (размеченное объединение) — это ключевой инструмент для работы со сложными структурами данных в TypeScript. Он позволяет создать тип, который может принимать одну из нескольких форм, при этом каждая форма имеет уникальное общее поле — дискриминант (обычно kind, type или tag).
Благодаря этому полю, TypeScript точно знает, с каким именно интерфейсом вы работаете в данный момент, и подсказывает только доступные для него свойства. Это делает код надежным и избавляет от множества проверок типов вручную.
- Модуль 1: Введение в TypeScript
- Модуль 2: Примитивные типы
- Модуль 3: Специальные типы
- Модуль 4: Массивы
- Модуль 5: Кортежи (Tuples)
- Модуль 6: Объекты
- Модуль 7: Функции
- Модуль 8: Union типы
- Модуль 9: Литеральные типы
- Модуль 10: Type Aliases
- Модуль 11: Интерфейсы
- Модуль 12: Type Guards и Narrowing
- Модуль 13: Enums
- Модуль 14: Классы
- Модуль 15: Generics — основы
- Модуль 16: Generics — ограничения
- Модуль 17: Utility Types — базовые
- Модуль 18: Utility Types — работа с Union
- Модуль 19: Utility Types — функции
- Модуль 20: Type Assertions
- Модуль 21: Keyof и Typeof операторы
- Модуль 22: Mapped Types
- Модуль 23: Conditional Types
- Модуль 24: Discriminated Unions
- Паттерн Discriminated Union.
- Exhaustiveness checking.
- Switch с Discriminated Unions.
- Модуль 25: Модули и типы
- Модуль 26: Declaration Files
- Модуль 27: Типизация асинхронного кода
- Модуль 28: Практические паттерны
1. Поиск дискриминанта
Перед вами два интерфейса TypeScript. Ваша задача — найти и отметить свойство, которое является общим дискриминантом для обоих интерфейсов. Дискриминант — это общее поле с литеральным типом, которое позволяет различать типы в размеченном объединении. Кликните на свойство (включая его имя и тип), которое выполняет эту роль в каждом интерфейсе. Не отмечайте другие свойства, которые не являются общими или не имеют литерального типа.
interface Circle {
{{kind: "circle"~|~t1}};
{{radius: number~|~t2}};
}
interface Square {
{{kind: "square"~|~t3}};
{{sideLength: number~|~t4}};
}2. Добавление тега
В этом задании вам нужно дополнить определение интерфейса для паттерна Discriminated Union в TypeScript. В предоставленном коде не хватает поля-дискриминанта, которое позволяет различать типы в объединении. Впишите в указанные места название этого поля (например, type или kind) и соответствующее ему литеральное строковое значение, чтобы код стал корректным и тип Shape мог использоваться как дискриминированное объединение.
interface Circle {
input1S: input2S;
radius: number;
}
interface Square {
kind: 'square';
sideLength: number;
}
type Shape = Circle | Square;
function getArea(shape: Shape): number {
if (shape.kind === 'circle') {
return Math.PI * shape.radius * shape.radius;
} else {
return shape.sideLength * shape.sideLength;
}
}3. Выбор правильного литерала
В этом задании вы отработаете использование discriminated unions в TypeScript. Ниже приведён код, определяющий объединённый тип Shape, который может быть либо Circle, либо Square. Создаются два объекта shape1 и shape2, но в них пропущены значения для поля `kind`. Ваша задача — выбрать из выпадающего списка правильные строковые литералы для `kind` в каждом объекте, чтобы они соответствовали остальным свойствам (radius для круга, sideLength для квадрата). Это упражнение поможет закрепить понимание того, как общее поле-дискриминант позволяет TypeScript различать типы в объединении.
type Shape = Circle | Square;
interface Circle {
kind: "circle";
radius: number;
}
interface Square {
kind: "square";
sideLength: number;
}
const shape1: Shape = {
kind: input1S,
radius: 10
};
const shape2: Shape = {
kind: input2S,
sideLength: 4
};4. Сопоставление типа и свойства
В этом задании вам нужно сопоставить значения дискриминанта (типы фигур) из discriminated union в TypeScript с уникальными свойствами, которые определены для каждого типа. В левой колонке приведены названия типов фигур, используемые как значения общего поля-дискриминанта, а в правой — их уникальные свойства. Сопоставьте каждый тип с соответствующими свойствами, обращая внимание на характерные для каждой фигуры атрибуты.
5. Ошибка в типе дискриминанта
В этом фрагменте кода TypeScript используется паттерн Discriminated Union для различения типов фигур. Однако в объявлении одного из типов допущена ошибка: поле-дискриминант имеет тип `string` вместо конкретного строкового литерала, что нарушает работу паттерна. Найдите и исправьте эту строку, чтобы TypeScript мог корректно сужать типы.
type Circle = { type: string; radius: number;}; type Square = { type: "square"; sideLength: number;}; type Shape = Circle | Square; function getArea(shape: Shape): number { if (shape.type === "circle") { return Math.PI * shape.radius ** 2; } else { return shape.sideLength ** 2; }}6. Сборка Union типа
Соберите из предложенных строк корректное определение discriminated union типа Shape, который представляет собой объединение типов Circle и Square. Каждый из этих типов должен иметь поле kind (строковый литерал) и своё уникальное поле (radius для Circle, sideLength для Square). Затем объявите тип Shape как объединение Circle и Square. Игнорируйте лишние строки, не относящиеся к определению этих типов.
interface Circle { kind: 'circle'; radius: number;}interface Square { kind: 'square'; sideLength: number;}type Shape = Circle | Square;interface Triangle {color: string;type Shape = Circle & Square;7. Структура паттерна
В этом коде TypeScript реализован паттерн Discriminated Union для обработки разных видов геометрических фигур. Разметьте выделенные фрагменты кода, указав для каждого, является ли он 'Общим интерфейсом', 'Дискриминантом' или 'Уникальным полем'. Общий интерфейс объединяет все типы объединения, дискриминант — это общее поле, определяющее конкретный тип, а уникальные поля — это свойства, специфичные для каждого типа.
interface {{Shape~|~t1}} {
{{kind~|~t2}}: 'circle' | 'rectangle' | 'triangle';
}
interface {{Circle~|~t3}} extends Shape {
kind: 'circle';
{{radius~|~t4}}: number;
}
interface {{Rectangle~|~t5}} extends Shape {
kind: 'rectangle';
{{width~|~t6}}: number;
{{height~|~t7}}: number;
}
interface {{Triangle~|~t8}} extends Shape {
kind: 'triangle';
{{base~|~t9}}: number;
{{height~|~t10}}: number;
}
type {{Geometry~|~t11}} = Circle | Rectangle | Triangle;