泛型参数扩展类型,但处于逆变位置,typescript可以';我不能统一它

泛型参数扩展类型,但处于逆变位置,typescript可以';我不能统一它,typescript,Typescript,我试图允许我的函数使用者使用更宽的类型,但我在反变位置和类型脚本中使用这种类型 简化代码: function wrapper<T extends Event = Event>(node: HTMLElement) { const handler = (e: T) => console.log(e.cancelable); node.addEventListener("click", handler); } 我如何表达我的意图以便typesc

我试图允许我的函数使用者使用更宽的类型,但我在反变位置和类型脚本中使用这种类型

简化代码:

function wrapper<T extends Event = Event>(node: HTMLElement) {
    const handler = (e: T) => console.log(e.cancelable);
    node.addEventListener("click", handler);
}
我如何表达我的意图以便typescript理解我

完整代码:

export function tracker(
  eventType: string,
  options?: boolean | AddEventListenerOptions
) {
  const stream: Stream<Event> = Stream.empty();

  function tracker(node: HTMLElement) {
    const handler = (event: Event) => stream.shamefullySendNext(event);
    node.addEventListener( eventType, handler, options);

    return {
      destroy: () => {
        node.removeEventListener(eventType, handler);
        stream.shamefullySendComplete();
      },
    };
  }

  return {
    stream,
    tracker,
  };
}
导出函数跟踪器(
eventType:string,
选项?:布尔| AddEventListenerOptions
) {
const stream:stream=stream.empty();
函数跟踪器(节点:HtmleElement){
const handler=(事件:event)=>stream.shamefullySendNext(事件);
addEventListener(事件类型、处理程序、选项);
返回{
销毁:()=>{
removeEventListener(事件类型,处理程序);
stream.shamefullySendComplete();
},
};
}
返回{
流动
追踪器,
};
}

您的问题相当令人困惑,但我相信您想要的是根据事件类型(即“单击”)而不是事件进行优化

我们永远不能安全地使用一个扩展事件的泛型
T
,因为这个
T
可以有任意的附加属性。考虑下面的例子:

interface MyEvent extends Event {
 customProperty: string
};

const handler = (e: MyEvent) => console.log(e.cancelable);
任何事件侦听器都无法执行回调
处理程序
,因为它们的
事件
缺少属性
自定义属性
。这就是为什么会出现“Type'Event'不可分配给Type'T”的错误

但是,我们可以细化事件类型,因为这是
addEventListener
所做的

addEventListener<K extends keyof HTMLElementEventMap>(
    type: K, 
    listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, 
    options?: boolean | AddEventListenerOptions
): void;
addEventListener(
    type: string, 
    listener: EventListenerOrEventListenerObject, 
    options?: boolean | AddEventListenerOptions
): void;

我不明白你为什么要使用泛型,或者你的真正意图是什么。是否可以使用
函数包装器(node:HTMLElement){const handler=(e:Event)=>console.log(e.cancelable);node.addEventListener(“click”,handler);}
,如图所示?如果没有,请详细说明到底出了什么问题。在实际代码中,有一个函数取代了console.log,将e推到用户土地上。用户可以定义泛型,并保证该值为特定类型。我在问题中添加了完整的代码。当您创建一个接受
T extends Event
的函数时,您会遇到这个错误,因为
T
可能类似于
接口MyEvent extends Event{customProperty:string}是事件侦听器永远无法实现的。您可以将其设置为事件类型的泛型(
K extensed keyof HTMLElementEventMap
),而不是
event
,我们可以将其传递给
addEventListener
,它是事件类型的泛型,但事件类型始终是
“click”
?你可以将泛型添加到你的
跟踪器
中,但实际上我没有得到任何错误,除了不知道从哪里导入
(因为你有
事件
而不是特定事件)。这是你想要的吗?在陈述了我的问题并阅读了你的回答后,我意识到我的整个前提是错误的。谢谢我仍然想知道是否可以让用户以某种方式断言事件类型。我在考虑这样一个场景,其中有人正在侦听某个web组件事件,它使用
CustomEvent
的某个子类调用处理程序。我担心typescript无法知道
CustomEvent
子类和事件名称之间的关系。。。
addEventListener<K extends keyof HTMLElementEventMap>(
    type: K, 
    listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, 
    options?: boolean | AddEventListenerOptions
): void;
addEventListener(
    type: string, 
    listener: EventListenerOrEventListenerObject, 
    options?: boolean | AddEventListenerOptions
): void;
export function tracker<K extends keyof HTMLElementEventMap>(
  eventType: K,
  options?: boolean | AddEventListenerOptions
) {
  const stream: Stream<HTMLElementEventMap[K]> = Stream.empty();

  function tracker(node: HTMLElement) {
    const handler = (event: HTMLElementEventMap[K]) => stream.shamefullySendNext(event);
    node.addEventListener<K>( eventType, handler, options);

    return {
      destroy: () => {
        node.removeEventListener(eventType, handler);
        stream.shamefullySendComplete();
      },
    };
  }

  return {
    stream,
    tracker,
  };
}