【问题标题】:Typescript generics: T extends X all of a sudden wants X to extend TTypescript 泛型:T 扩展 X 突然想要 X 扩展 T
【发布时间】:2020-01-06 22:52:43
【问题描述】:

我收到一个错误,我的接口 Event 应该实现 MyEvent 的所有属性,而实际上我希望 TS 检查 MyEvent 实现 Event

我对泛型的理解是我可以定义一个接受类型T extends X 作为参数的函数,但现在它说的是X doesn't extend T

背景

我正在创建一个简单的事件管理器:

// 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'. 

这里发生了什么?我希望事件管理器接受任何类型的事件,因此是&lt;T extends Event&gt;,但现在它说Event 应该具有MyEvent 的所有属性,而不是MyEvent 应该具有所有Event 接口?

(PS:如果我接受Event接口而不是接受类型T,也会发生同样的情况。

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    on 需要定义为泛型。像这样的:

    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);
    });
    

    我认为这只是您对语法的误解。

    【讨论】:

    • 美丽。在这上面花了两个半小时,我所要做的就是把声明移到左边 20 个字符哈哈。确实,它有效。事实上,我发现必须在 on 而不是回调函数上声明类型很奇怪,但我想那是我对泛型的不那么熟练。
    • 您能否回答有关此问题的最后一个问题以获得假想的奖励积分?如果我声明on 方法如下:on(eventName: string, cb: (event: Event) =&gt; void) {,我仍然无法将事件传递给回调。它说“类型'事件'缺少类型'MyEvent'的以下属性:getFooBar”。我再次期待这会起作用,因为MyEvent 扩展了Event
    • 对我来说,使用:on(eventName: string, cb: (event: Event) =&gt; void) {}eventManager.on('test', (e: MyEvent) =&gt; {}); 不会出错。如果你能在 typescript playground 或 stackblitz 中准备一些代码就好了。
    • 嘿,对不起。我这里有一个例子:codesandbox.io/s/2t78m
    • 会的,谢谢你回答我原来的问题!
    猜你喜欢
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多