Вложенное троичное условие внутри типа Typescript расширяется - PullRequest
1 голос
/ 29 июня 2019

Я перехожу с разработки на JavaScript к работодателю, который обеспечивает типизацию TypeScript.Я создал Interface для модели, которая содержит типичный .on(event, handler).

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

interface Model {
    ...
    on<T extends "added" | "failed" | "initialized" | "changed" | "removed"> (
        event: T,
        handler: T extends "changed" | "removed"
                 ? (T extends "changed"
                     ? (model: Model, entity: Entity, data: object) => void
                     : (model: Model, id: string) => void)
                 : (model: Model, entity: Entity) => void,
        context?: object
    ): void
}

Похоже, что есть способ иметь разные подписи для аргумента handler, на основе которого было передано event.

Кажется, это работает, но мне интересноесли есть другой шаблон для написания этого, так что его немного легче читать и понимать.

1 Ответ

1 голос
/ 30 июня 2019

Я бы подумал об использовании интерфейса отображения и индексации в нем, поскольку операция «преобразование строкового литерала в определенный тип» естественным образом предоставляется вам в TypeScript по типам объектов.В то время как вы можете использовать условные типы, чтобы сделать это, это, как правило, труднее читать и поддерживать.

В качестве первого шага к рефакторингу я бы сделал что-то вроде этого:

// use a mapping from event name to event handler type
interface EventHandlerMap {
  added: (model: Model, entity: Entity) => void;
  failed: (model: Model, entity: Entity) => void;
  initialized: (model: Model, entity: Entity) => void;
  changed: (model: Model, entity: Entity, data: object) => void;
  removed: (model: Model, id: string) => void;
}

interface Model {
  on<T extends keyof EventHandlerMap>(
    event: T,
    handler: EventHandlerMap[T], // index into the mapping
    context?: object
  ): void;
}

Вы можете убедиться в том, что он действует аналогично (или использовать ссылку на код наконец, чтобы увидеть).Интерфейс EventHandlerMap - это просто помощник, которого вы фактически не назначаете никаким объектам.Но он описывает преобразование параметра Model.on() event типа T в параметр handler.И мы используем типы поиска , чтобы извлечь тип handler как EventHandlerMap[T].

Может быть возможно провести дальнейший рефакторинг этого ... например, все эти функции возвращают void, а первый параметр - Model;возможно, вы могли бы заставить EventHandlerMap только отслеживать, что отличается между различными событиями, а затем использовать более сложные типы манипуляций, но это может быть больше проблем, чем оно того стоит.

Хорошо, надеюсь, это поможет;удачи!

Ссылка на код

...