Определение типа payload в зависимости от значения action.type

Опишите отображение ActionType → тип payload и постройте размеченное объединение через mapped type. Так type и payload останутся связанными даже при объединении нескольких вариантов.

Короткий ответ

Что ответить на собеседовании

Опишите отображение ActionType → тип payload и постройте размеченное объединение через mapped type. Так type и payload останутся связанными даже при объединении нескольких вариантов.

Подробный разбор

Ответ с пояснениями

Условие

Необходимо описать тип Action, чтобы тип свойства payload автоматически выводился из конкретного значения action.type.

enum ActionType {
    one = "one",
    two = "two",
}

const reducer = <T extends ActionType>(
    state: State,
    action: Action<T>,
): State

action = { type, payload }

type Action = ?

В задаче требуется использовать возможности TypeScript (универсальные типы, условные типы, маппинг) для привязки корректного типа payload к каждому варианту ActionType.

Ответ

Опишите отображение ActionType → тип payload и постройте размеченное объединение через mapped type. Так type и payload останутся связанными даже при объединении нескольких вариантов.

// Иллюстративные payload: замените реальными типами домена.
type PayloadByType = {
  [ActionType.one]: string;
  [ActionType.two]: number;
};
type Action<T extends ActionType = ActionType> = {
  [K in T]: { type: K; payload: PayloadByType[K] }
}[T];
const first: Action = { type: ActionType.one, payload: 'text' };
// { type: ActionType.one, payload: 123 } не соответствует Action

Простая пара type: T; payload: PayloadByType[T] при T-объединении может потерять корреляцию. Для удобного сужения внутри reducer принимайте action: Action и делайте switch по type; generic T полезен на границе конкретного действия, но не всегда сужается внутри реализации.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее