generi c расширяет параметр, не назначаемый типу аргумента - PullRequest
1 голос
/ 06 марта 2020

Я пытаюсь использовать extends в параметре generi c для индексации объекта, но получаю следующую ошибку:

Аргумент типа 'IHandlerMap [K]' равен нельзя назначить параметру типа «BasicHandler». Тип 'BasicHandler | KeyPressHandler 'нельзя назначить типу' BasicHandler '. Тип «KeyPressHandler» нельзя назначить типу «BasicHandler» .ts (2345)

Код:

export type BasicHandler = () => void;
export type KeyPressHandler = (keyCode: number) => void;

interface IHandlerMap {
  OnTick: BasicHandler;
  OnKeyDown: KeyPressHandler;
}

type HandlersType = {[key in keyof IHandlerMap]: IHandlerMap[key][]};

export class EventManager {
  private readonly handlers: HandlersType = {
    OnTick: [],
    OnKeyDown: [],
  };

  public addHandler<K extends keyof IHandlerMap>(
    type: K,
    handler: IHandlerMap[K]
  ): {
    this.handlers[type].push(handler); // Error is occuring here.
  }
}

Похоже, что TS может только определить, что свойство объекта является массивом BasicHandler типов, когда это может быть BasicHandler ИЛИ KeyPressHandler?

Как использовать keyof для индексации интерфейса (handler: IHandlerMap[K]) и затем использовать этот параметр для pu sh на ключ объекта, который также type 'd (this.handlers[type].push(handler)?

У меня много проблем с объяснением того, что я пытаюсь сделать, это неправильный способ go об этом? Если да, то какова альтернатива?

1 Ответ

1 голос
/ 06 марта 2020

Я предполагаю, что тип выражения this.handlers[type] вызывает вашу ошибку:

В теле функции addHandler мы не знаем, какое из двух значений "OnTick" или "OnKeyDown" свойство type имеет, поэтому для доступа к свойству предполагается его базовый тип keyof IHandlerMap или "OnTick" | "OnKeyDown". Доступ к свойству this.handlers[type] будет преобразован в тип HandlersType[keyof IHandlerMap], который равен BasicHandler[] | KeyPressHandler[].

Теперь, когда мы вызываем this.handlers[type].push, метод push может быть вызван либо с помощью BasicHandler[], либо KeyPressHandler[], так что его типом является union обоих push методов:

| (...items: BasicHandler[]): number 
| (...items: KeyPressHandler[]): number

Начиная с TS 3.3, вы можете фактически вызывать union тип функций , но их параметры пересекаются (&). Сигнатура push выглядит примерно так:

(method) Array<T>.push(items: (BasicHandler & KeyPressHandler)[]): number

BasicHandler не имеет параметров функции, KeyPressHandler один. Таким образом, пересечение приводит к ... нет ожидаемых параметров. Вы можете добавить аргумент, например s: string к BasicHandler, и он станет более очевидным (наведите курсор на push затем).

Что мы можем сделать?

Использовать дополнительную переменную для this.handlers с типом HandlersTypeMixed или используйте его для this.handlers напрямую. Примечание: (BasicHandler | KeyPressHandler)[] !== BasicHandler[] | KeyPressHandler[]. Только первое не приведет к объединению типов функций и не позволит push. Детская площадка

type HandlersTypeMixed = { [key in keyof IHandlerMap]: (BasicHandler | KeyPressHandler)[] }

public addHandler<K extends keyof IHandlerMap>(
    type: K,
    handler: IHandlerMap[K]
) {
    const hs: HandlersTypeMixed  = this.handlers
    hs[type].push(handler);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...