Обобщение Typescript: T расширяет X внезапно, хочет, чтобы X расширял T - PullRequest
2 голосов
/ 07 января 2020

Я получаю сообщение об ошибке, что мой интерфейс Event должен реализовать все свойства MyEvent, в то время как на самом деле я хочу, чтобы TS проверил, что MyEvent реализует Event.

В моем понимании обобщений я мог определить функцию, которая принимает тип T extends X в качестве аргумента, но теперь говорится, что X doesn't extend T.

Фон

I создаю простой менеджер событий:

// imports..

export interface Event {
  getName: () => string;
}

export class EventManager {
  private callbacks; // Typing is unimportant for this example.

  on(eventName: string, cb: <T extends Event>(event: T) => void) {
    // some code..

    this.callbacks[eventName].push(cb);
  }

  // more code..
}

Затем я пытаюсь прослушать событие (которое вызывает ошибку, которая меня смущает):

class MyEvent implements Event {
  // Implement Event interface method.
  getName(): string {
    return 'a';
  }

  // Add other random method.
  getFooBar(): string {
    return 'b';
  }
}

const eventManager = new EventManager();
eventManager.on('test', (e: MyEvent) => {
  console.log(e);
});

Ошибка:

TS2345: Argument of type '(e: MyEvent) => void' is not assignable to parameter of type '<T extends Event>(event: T) => void'.   
  Types of parameters 'e' and 'event' are incompatible.     
    Type 'T' is not assignable to type 'MyEvent'.       
      Property 'getFooBar' is missing in type 'Event' but required in type 'MyEvent'. 

Что здесь происходит? Я хочу, чтобы менеджер событий принимал события любого типа, следовательно, <T extends Event>, но теперь он говорит, что Event должен иметь все свойства MyEvent, а MyEvent должен иметь весь интерфейс Event?

(PS: то же самое происходит, если вместо принятия типа T я принимаю Event интерфейс).

1 Ответ

1 голос
/ 07 января 2020

on необходимо определить как обобщенный c. Примерно так:

interface Event {
  getName: () => string;
}

class EventManager {
  private callbacks; // Typing is unimportant for this example.

  on<T extends Event>(eventName: string, cb: (event: T) => void) {
    // some code..
  }
  // more code..
}

class MyEvent implements Event {
  // Implement Event interface method.
  getName(): string {
    return 'a';
  }

  // Add other random method.
  getFooBar(): string {
    return 'b';
  }
}

class YourEvent implements Event {
  // Implement Event interface method.
  getName(): string {
    return 'a';
  }

  // Add other random method.
  getBarFoo(): string {
    return 'b';
  }
}

const eventManager = new EventManager();
eventManager.on<MyEvent>('test', (e: MyEvent) => {
  console.log(e);
});

eventManager.on<YourEvent>('test', (e: YourEvent) => {
  console.log(e);
});

Я думаю, это просто недопонимание синтаксиса с вашей стороны.

...