Аргумент типа '(event: BlahEvent) => void' не может быть назначен параметру типа 'EventListenerOrEventListenerObject' - PullRequest
0 голосов
/ 18 декабря 2018

Я прочитал и попробовал предложения, найденные в Аргумент типа '(e: CustomEvent) => void' нельзя назначить параметру типа 'EventListenerOrEventListenerObject' , но он не смог разумно применитьих в моей ситуации

Я взял на себя проект TS2.0, и я собираюсь перейти на 3.1 с ним.Я читал вокруг об ошибке в названии и вроде понимаю, почему это происходит, но мои знания машинописи на этом этапе ограничены

У меня есть следующие классы:

Кажется, что EventTargetImplкласс для управления коллекцией прослушивателей событий

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

InputWrapper.Этот класс, кажется, имеет / содержит HTML-элемент и либо регистрирует стандартные обработчики для событий элемента, либо заменяет их на прикрепленные к нему обработчики событий локального типа, названных в InputEvent

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 о том, что я могу объявлять слияние в моих локальных событиях как тип InputEvent, а затем использовать строго типизированную перегрузку addEventHandler, а не строго типизированную, но я не могу понять, где и как это сделать ву меня есть иерархия объектов / наследования

Я также попробовал предложение Фредерика Краутвальда о добавлении as (e: Event) => void) в конец встроенной функции, но TypeScript изменился на жалобу

Преобразование типа '(событие: InputEvent) => void 'to type' (e: Event) => void 'может быть ошибкой, поскольку ни один из типов в достаточной степени не совпадает с другим

Модифицированная форма предложения JacobEvelyn больше всего похожа на Iсделал бы это в C #, если бы у меня был определенный тип, упакованный в общий:

inputWrapper.addEventListener(InputEvent.TYPE_UP, (event: Event) => {
   let iv: InputEvent = (event as InputEvent); 
   this.handleMouseUp(iv.coords.x, iv.coords.y); 
});

Но снова я получаю ошибку "ни один тип не совпадает с другим"

1 Ответ

0 голосов
/ 18 декабря 2018

Как устранить ошибку «ни один тип не перекрывает достаточно другой»

Предварительное предупреждение: утверждения типа , как правило, небезопасны для типа.Компилятор часто не позволяет вам делать что-то, потому что это ошибка для вас.Однако есть также много ситуаций, в которых вы уверены, что что-то безопасно, но компилятор не убежден.И вы можете использовать утверждения типа, чтобы заставить компилятор принять вашу версию истины.Это все хорошо, если только вы не ошибаетесь, и в этом случае вы можете ожидать сумасшедшее поведение во время выполнения, и вы не должны обвинять плохой компилятор, который пытался вас предупредить.Компилятор не такой умный, как человек, поэтому утверждения часто необходимы.С этого момента я предполагаю, что утверждение, которое вы хотите сделать, достаточно безопасно.

Вот общий пример, который дает ошибку, с которой вы столкнулись.

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 нельзя использовать для прямого преобразования из одного типа в несвязанный тип , который не является ни узким, ни широким (поэтому я могу прямо утверждать, что кошка является животным, и я могу прямо утверждать, чтоanimal - это собака, но я не могу прямо утверждать, что кошка - это собака.

Ключ к решению этой проблемы также упоминается в сообщении об ошибке: «сначала преобразовать выражение в unknown»:

function assert<T, U>(t: T): U {
  return t as unknown as U; // works
}

Ошибка ушла, потому что мы расширили t от типа T вплоть до типа top unknown, а затем сузились от unknown до типа U.Каждый из этих шагов разрешен, но вы не можете пропустить средний шаг.(Я не могу сказать «этот кот - собака», но я могу сказать «этот кот - животное, которое является собакой».)

Есть и другие возможные промежуточные типы, которые вы можете использовать;это просто должен быть общий супертип или общий подтип двух несвязанных типов:

  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), так что не чувствуйте слишком плохим в использовании.Громоздкая природа в первую очередь заставляет вас задуматься о том, что вы делаете: вы уверены , что это значение можно рассматривать как этот тип?Если нет, то другое решение будет лучше, чем утверждение типа.Если так, то продолжай!

Надеюсь, это поможет;удачи!

...