“(event: BlahEvent) => void”类型的参数不可分配给 'EventListenerOrEventListenerObject' 类型的参数
Argument of type '(event: BlahEvent) => void' is not assignable to parameter of type 'EventListenerOrEventListenerObject'
我已经阅读并尝试了 中的建议,但无法明智地将它们应用到我的情况中
我已经接管了一个 TS2.0 项目,我希望将其转移到 3.1。我已经阅读了有关标题中的错误的信息,并有点理解它发生的原因,但此时我的打字知识有限
我有这些 classes:
EventTargetImpl 似乎是一个 class 用于管理 collection 事件侦听器
class EventTargetImpl implements EventTarget {
private eventListeners: any = {};
public addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void {
if (!this.eventListeners.hasOwnProperty(type))
this.eventListeners[type] = [];
this.eventListeners[type].push(listener);
}
public dispatchEvent(event: Event): boolean {
var type = event.type;
if (!this.eventListeners.hasOwnProperty(type)) {
this.eventListeners[type] = [];
}
for (var i = 0; i < this.eventListeners[type].length; i++) {
this.eventListeners[type][i].call(this, event);
}
return true;
}
public removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void {
if (!this.eventListeners.hasOwnProperty(type))
return;
var listenerIndex = this.eventListeners[type].indexOf(listener);
if (listenerIndex === -1)
return;
this.eventListeners[type].splice(listenerIndex, 1);
}
}
InputEvent class 定义事件名称的常量字符串,它们是事件的某种本地版本。
class InputEvent extends EventImpl
{
public static TYPE_UP = "up";
constructor(type: string) {
super(type);
}
}
..但除此之外,除了扩展 EventImpl 之外似乎没有做太多事情:
class EventImpl implements Event
{
public bubbles: boolean;
public cancelBubble: boolean;
public cancelable: boolean;
public currentTarget: EventTarget;
public defaultPrevented: boolean;
public eventPhase: number;
public isTrusted: boolean;
public returnValue: boolean;
public srcElement: Element;
public target: EventTarget;
public timeStamp: number;
public type: string;
public initEvent(eventTypeArg: string, canBubbleArg: boolean, cancelableArg: boolean): void { throw "not implemented";}
public preventDefault(): void {
this.defaultPrevented = true;
}
public stopImmediatePropagation(): void { throw "not implemented"; }
public stopPropagation(): void { throw "not implemented";}
public AT_TARGET: number;
public BUBBLING_PHASE: number;
public CAPTURING_PHASE: number;
constructor(type: string) {
this.type = type;
}
}
输入包装器。 class 似乎是 have/hold 一个 HTML 元素,并且要么为元素的事件注册标准处理程序,要么用 InputEvent [= 中命名的本地类型事件的附加到自身的处理程序替换它们20=]
class InputWrapper extends EventTargetImpl {
constructor(private element: HTMLElement) {
super();
this.attachListeners();
}
private attachListeners(): void {
var detachGlobalListeners: () => void;
var attachGlobalListeners: () => void;
var mouseUpEventHandler = (event) => {
var point = this.normaliseMouseEventCoords(event);
this.handleMouseUp(point.x, point.y, event, InputType.Mouse);
detachGlobalListeners();
};
this.element.addEventListener("mouseup", (event) => {
if (!this.globalMode) {
this.handleMouseUp(event.offsetX, event.offsetY, event, InputType.Mouse);
}
});
detachGlobalListeners = () => {
this.globalMode = false;
window.removeEventListener("mouseup", mouseUpEventHandler);
};
attachGlobalListeners = () => {
this.globalMode = true;
window.addEventListener("mouseup", mouseUpEventHandler);
};
}
private handleMouseUp(x: number, y: number, event: Event, inputType: InputType): void {
event.stopPropagation();
event.preventDefault();
this.dispatchEvent(new InputEvent(InputEvent.TYPE_UP, { x: x, y: y }, inputType));
}
}
这是使用它的地方,也是我得到错误的地方。我在上面的代码行中的 dispatchEvent 调用中也遇到了类似的错误:
var inputWrapper = new InputWrapper(this.foreground);
inputWrapper.addEventListener(InputEvent.TYPE_UP, (event: InputEvent) => {
this.handleMouseUp(event.coords.x, event.coords.y);
});
我链接了一个我已经看过的 SO 答案;我喜欢 jcalz 的建议,我可以 declaration-merge 在我的本地事件中作为 InputEvent 类型,然后使用 addEventHandler 的强类型重载,而不是字符串类型的重载,但我无法解决 where/how要在 object/inheritance 层次结构中执行此操作,我有
我还尝试了 FrederikKrautwald 的建议,将 as (e: Event) => void)
附加到内联函数的末尾,但 TypeScript 更改为抱怨
Conversion of type '(event: InputEvent) => void' to type '(e: Event) => void' may be a mistake because neither type sufficiently overlaps with the other
JacobEvelyn 建议的修改形式最像我在 C# 中所做的,如果我将特定类型封装在通用类型中:
inputWrapper.addEventListener(InputEvent.TYPE_UP, (event: Event) => {
let iv: InputEvent = (event as InputEvent);
this.handleMouseUp(iv.coords.x, iv.coords.y);
});
但我再次收到 "neither type sufficiently overlaps with the other" 错误
如何解决“两种类型都没有充分重叠”的错误
初步警告:type assertions 通常不是类型安全的。编译器经常不允许你做一些事情,因为你这样做是错误的。但是,也有很多情况,您确信某些东西是安全的,但编译器并不相信。您可以使用类型断言强制编译器接受您的真实版本。这一切都很好,除非你碰巧错了,在这种情况下,你可以预料到疯狂的运行时行为,你不应该责怪试图警告你的可怜的编译器。但是,编译器并不像人类那么聪明,因此断言通常是必需的。从现在开始,我假设你想要做出的断言是足够安全的。
这是一个通用示例,给出了您遇到的错误。
function assert<T, U>(t: T): U {
return t as U; // error
// [ts] Conversion of type 'T' to type 'U' may be a mistake because
// neither type sufficiently overlaps with the other. If this was
// intentional, convert the expression to 'unknown' first.
}
我们试图断言 T
类型的值是 U
类型的值,但我们得到了“两种类型都没有充分重叠”的错误。基本上,类型断言可用于将类型 扩展 为超类型,这总是安全的,因为您变得更加通用(每只狗都可以被正确地称为动物);并且它们还可以用于 将类型缩小 为更具体的类型,这是不安全的,因为你更具体(不是每只动物都可以正确地称为狗)。 .. 这种类型安全性的缺乏是有意为之的,也是我们首先拥有断言的原因。但是在 TypeScript 中,类型断言不能用于直接从一种类型转换为既不窄也不宽的 unrelated 类型(所以我可以直接断言猫是动物,我可以直接断言动物是狗,我不能直接断言猫是狗。
错误信息中也提到了解决这个问题的关键:“首先将表达式转换为unknown
”:
function assert<T, U>(t: T): U {
return t as unknown as U; // works
}
错误消失了,因为我们将 t
从类型 T
一直扩大到 top type unknown
,然后从 [=15] 缩小=] 向下输入 U
。这些步骤中的每一个都是允许的,但您不能跳过中间步骤。 (我不能说“this cat is a dog”但我可以说“this cat is an animal which is a dog”。)
您还可以使用其他可能的中间类型;它必须是两个不相关类型的公共超类型或公共子类型:
return t as unknown as U; // okay, widen T to top type unknown, and narrow unknown to U
return t as (T | U) as U; // okay, widen T to (T | U), and narrow (T | U) to U
return t as never as U; // okay, narrow T to bottom type never, and widen never to U
return t as (T & U) as U; // okay, narrow T to (T & U), and widen (T & U) to U
return t as any as U; // okay, any is both top-like and bottom-like,
// so you are, uh, "narrowidening" it through any
这个中间人断言是一种相当普遍的做法(尤其是t as any as U
,因为unknown
在TypeScript 3.0中只有introduced),所以不要觉得太 不好用。繁琐的本质主要是迫使你思考你在做什么:你确定这个值可以被视为这个类型吗?如果没有,其他一些解决方案会比类型断言更好。如果是,那就继续!
希望对您有所帮助;祝你好运!
我已经阅读并尝试了
我已经接管了一个 TS2.0 项目,我希望将其转移到 3.1。我已经阅读了有关标题中的错误的信息,并有点理解它发生的原因,但此时我的打字知识有限
我有这些 classes:
EventTargetImpl 似乎是一个 class 用于管理 collection 事件侦听器
class EventTargetImpl implements EventTarget {
private eventListeners: any = {};
public addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void {
if (!this.eventListeners.hasOwnProperty(type))
this.eventListeners[type] = [];
this.eventListeners[type].push(listener);
}
public dispatchEvent(event: Event): boolean {
var type = event.type;
if (!this.eventListeners.hasOwnProperty(type)) {
this.eventListeners[type] = [];
}
for (var i = 0; i < this.eventListeners[type].length; i++) {
this.eventListeners[type][i].call(this, event);
}
return true;
}
public removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void {
if (!this.eventListeners.hasOwnProperty(type))
return;
var listenerIndex = this.eventListeners[type].indexOf(listener);
if (listenerIndex === -1)
return;
this.eventListeners[type].splice(listenerIndex, 1);
}
}
InputEvent class 定义事件名称的常量字符串,它们是事件的某种本地版本。
class InputEvent extends EventImpl
{
public static TYPE_UP = "up";
constructor(type: string) {
super(type);
}
}
..但除此之外,除了扩展 EventImpl 之外似乎没有做太多事情:
class EventImpl implements Event
{
public bubbles: boolean;
public cancelBubble: boolean;
public cancelable: boolean;
public currentTarget: EventTarget;
public defaultPrevented: boolean;
public eventPhase: number;
public isTrusted: boolean;
public returnValue: boolean;
public srcElement: Element;
public target: EventTarget;
public timeStamp: number;
public type: string;
public initEvent(eventTypeArg: string, canBubbleArg: boolean, cancelableArg: boolean): void { throw "not implemented";}
public preventDefault(): void {
this.defaultPrevented = true;
}
public stopImmediatePropagation(): void { throw "not implemented"; }
public stopPropagation(): void { throw "not implemented";}
public AT_TARGET: number;
public BUBBLING_PHASE: number;
public CAPTURING_PHASE: number;
constructor(type: string) {
this.type = type;
}
}
输入包装器。 class 似乎是 have/hold 一个 HTML 元素,并且要么为元素的事件注册标准处理程序,要么用 InputEvent [= 中命名的本地类型事件的附加到自身的处理程序替换它们20=]
class InputWrapper extends EventTargetImpl {
constructor(private element: HTMLElement) {
super();
this.attachListeners();
}
private attachListeners(): void {
var detachGlobalListeners: () => void;
var attachGlobalListeners: () => void;
var mouseUpEventHandler = (event) => {
var point = this.normaliseMouseEventCoords(event);
this.handleMouseUp(point.x, point.y, event, InputType.Mouse);
detachGlobalListeners();
};
this.element.addEventListener("mouseup", (event) => {
if (!this.globalMode) {
this.handleMouseUp(event.offsetX, event.offsetY, event, InputType.Mouse);
}
});
detachGlobalListeners = () => {
this.globalMode = false;
window.removeEventListener("mouseup", mouseUpEventHandler);
};
attachGlobalListeners = () => {
this.globalMode = true;
window.addEventListener("mouseup", mouseUpEventHandler);
};
}
private handleMouseUp(x: number, y: number, event: Event, inputType: InputType): void {
event.stopPropagation();
event.preventDefault();
this.dispatchEvent(new InputEvent(InputEvent.TYPE_UP, { x: x, y: y }, inputType));
}
}
这是使用它的地方,也是我得到错误的地方。我在上面的代码行中的 dispatchEvent 调用中也遇到了类似的错误:
var inputWrapper = new InputWrapper(this.foreground);
inputWrapper.addEventListener(InputEvent.TYPE_UP, (event: InputEvent) => {
this.handleMouseUp(event.coords.x, event.coords.y);
});
我链接了一个我已经看过的 SO 答案;我喜欢 jcalz 的建议,我可以 declaration-merge 在我的本地事件中作为 InputEvent 类型,然后使用 addEventHandler 的强类型重载,而不是字符串类型的重载,但我无法解决 where/how要在 object/inheritance 层次结构中执行此操作,我有
我还尝试了 FrederikKrautwald 的建议,将 as (e: Event) => void)
附加到内联函数的末尾,但 TypeScript 更改为抱怨
Conversion of type '(event: InputEvent) => void' to type '(e: Event) => void' may be a mistake because neither type sufficiently overlaps with the other
JacobEvelyn 建议的修改形式最像我在 C# 中所做的,如果我将特定类型封装在通用类型中:
inputWrapper.addEventListener(InputEvent.TYPE_UP, (event: Event) => {
let iv: InputEvent = (event as InputEvent);
this.handleMouseUp(iv.coords.x, iv.coords.y);
});
但我再次收到 "neither type sufficiently overlaps with the other" 错误
如何解决“两种类型都没有充分重叠”的错误
初步警告:type assertions 通常不是类型安全的。编译器经常不允许你做一些事情,因为你这样做是错误的。但是,也有很多情况,您确信某些东西是安全的,但编译器并不相信。您可以使用类型断言强制编译器接受您的真实版本。这一切都很好,除非你碰巧错了,在这种情况下,你可以预料到疯狂的运行时行为,你不应该责怪试图警告你的可怜的编译器。但是,编译器并不像人类那么聪明,因此断言通常是必需的。从现在开始,我假设你想要做出的断言是足够安全的。
这是一个通用示例,给出了您遇到的错误。
function assert<T, U>(t: T): U {
return t as U; // error
// [ts] Conversion of type 'T' to type 'U' may be a mistake because
// neither type sufficiently overlaps with the other. If this was
// intentional, convert the expression to 'unknown' first.
}
我们试图断言 T
类型的值是 U
类型的值,但我们得到了“两种类型都没有充分重叠”的错误。基本上,类型断言可用于将类型 扩展 为超类型,这总是安全的,因为您变得更加通用(每只狗都可以被正确地称为动物);并且它们还可以用于 将类型缩小 为更具体的类型,这是不安全的,因为你更具体(不是每只动物都可以正确地称为狗)。 .. 这种类型安全性的缺乏是有意为之的,也是我们首先拥有断言的原因。但是在 TypeScript 中,类型断言不能用于直接从一种类型转换为既不窄也不宽的 unrelated 类型(所以我可以直接断言猫是动物,我可以直接断言动物是狗,我不能直接断言猫是狗。
错误信息中也提到了解决这个问题的关键:“首先将表达式转换为unknown
”:
function assert<T, U>(t: T): U {
return t as unknown as U; // works
}
错误消失了,因为我们将 t
从类型 T
一直扩大到 top type unknown
,然后从 [=15] 缩小=] 向下输入 U
。这些步骤中的每一个都是允许的,但您不能跳过中间步骤。 (我不能说“this cat is a dog”但我可以说“this cat is an animal which is a dog”。)
您还可以使用其他可能的中间类型;它必须是两个不相关类型的公共超类型或公共子类型:
return t as unknown as U; // okay, widen T to top type unknown, and narrow unknown to U
return t as (T | U) as U; // okay, widen T to (T | U), and narrow (T | U) to U
return t as never as U; // okay, narrow T to bottom type never, and widen never to U
return t as (T & U) as U; // okay, narrow T to (T & U), and widen (T & U) to U
return t as any as U; // okay, any is both top-like and bottom-like,
// so you are, uh, "narrowidening" it through any
这个中间人断言是一种相当普遍的做法(尤其是t as any as U
,因为unknown
在TypeScript 3.0中只有introduced),所以不要觉得太 不好用。繁琐的本质主要是迫使你思考你在做什么:你确定这个值可以被视为这个类型吗?如果没有,其他一些解决方案会比类型断言更好。如果是,那就继续!
希望对您有所帮助;祝你好运!