繁体   English   中英

类型中缺少属性,但类型中需要属性

[英]Property is missing in type but required in type

我正在尝试在 TypeScript 上实现简单的事件调度程序。

我的自定义类型声明如下:

events.d.ts

type AppEvent = { [key: string]: any }

type AppEventListener<T> = <T extends AppEvent>(event: T) => void;

当我在这个 function 中通过任何 object

   public addListener<T extends AppEvent>(event: T, listener: AppEventListener<T>)

我收到以下错误:

Argument of type '(event: TestEvent) => void' is not assignable to parameter of type 'AppEventListener<typeof TestEvent>'.
   Types of parameters 'event' and 'event' are incompatible.
     Type 'T' is not assignable to type 'TestEvent'.
       Property 'name' is missing in type 'AppEvent' but required in type 'TestEvent'.

所以,这种类型的AppEvent不能有任何额外的属性。 如何让它发挥作用? 任何帮助表示赞赏。

完整代码示例:

class EventDispatcher {
  private listeners: Map<AppEvent, Array<AppEventListener<AppEvent>>>

  constructor() {
    this.listeners = new Map();
  }

  public dispatch<T extends AppEvent>(event: T): void {
    const listeners = this.listeners.get(event.constructor);
    if (listeners) {
      listeners.forEach((callback) => {
        callback(event);
      });
    }
  }

  public addListener<T extends AppEvent>(event: T, listener: AppEventListener<T>): void {
    let listeners = this.listeners.get(event);
    if (!listeners) {
      listeners = [listener];
      this.listeners.set(event, listeners);
    } else {
      listeners.push(listener);
    }
  }
}

class TestEvent {
  public name: string = ''
}

const dispatcher = new EventDispatcher();
const listener = (event: TestEvent) => {
  console.dir(event);
};
dispatcher.addListener(TestEvent, listener);

const event = new TestEvent('name');
dispatcher.dispatch(event);

看起来你应该让AppEventLister成为泛型类型,引用非泛型 function,如下所示:

type AppEventListener<T> = (event: T) => void;

您是说“ AppEventListener<T>将接受T类型的事件”。 这就是你想要的,对吧?


您的原始定义是泛型类型,指的是泛型 function,具有两个不同的同名泛型参数,相当于

type AppEventListenerBad<T> = <U>(event: U) => void;

(重命名不会更改类型;它只是让类型参数名称阴影发生的情况更清楚)意味着“ AppEventListener<T>将完全忽略T并接受调用者想要指定的任何类型U的事件",这不太可能是你的意思。 这就是您的错误的来源: (event: TestEvent) => void不可分配给<U>(event: U) => void


一旦你这样做了,很多其他的问题就解决了,但它们可能会带来其他的问题。 一个主要的问题是Map的标准库类型表示从K类型的键到V类型的值的非常基本的映射。 它没有办法说K map 的某些子类型的键与以编程方式确定的V子类型的值。 在您的情况下,您可以为使用Map的方式创建一个新界面:

interface AppEventListenerMap {
  get<T>(x: T): Array<AppEventListener<T>> | undefined;
  set<T>(x: T, val: Array<AppEventListener<T>>): void;
}

然后在EventDispatcher中将listeners属性AppEventListenerMap类型的值:

class EventDispatcher {
  private listeners: AppEventListenerMap;

  constructor() {
    this.listeners = new Map();
  }

这将主要使您的代码示例工作,除了您似乎有时使用event作为键,而在其他时候使用event.constructor作为键这一事实。 这种不一致似乎是错误的,您可能需要准确地确定类型关系才能使其正常工作。

无论如何,希望这会有所帮助; 祝你好运!

Playground 代码链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM