constructor(type, dict) {
    if (dict) {
      if (dict instanceof Map) {
        // Take properties from dict if present.
        for (const key of dict.keys()) {
          Object.defineProperty(this, key, {
            value: dict.get(key),
            writable: true,
            enumerable: true,
          });
        }
      } else {
        // For backwards compatibility with external apps that may make use of
        // this public constructor, this should still accept generic objects.
        const obj = shaka.util.FakeEvent.recastDictAsObject_(dict);
        for (const key in obj) {
          Object.defineProperty(this, key, {
            value: obj[key],
            writable: true,
            enumerable: true,
          });
        }
      }
    }

    // The properties below cannot be set by the dict.  They are all provided
    // for compatibility with native events.

    /** @const {boolean} */
    this.bubbles = false;

    /** @type {boolean} */
    this.cancelable = false;

    /** @type {boolean} */
    this.defaultPrevented = false;

    /**
     * According to MDN, Chrome uses high-res timers instead of epoch time.
     * Follow suit so that timeStamps on FakeEvents use the same base as
     * on native Events.
     * @const {number}
     * @see https://developer.mozilla.org/en-US/docs/Web/API/Event/timeStamp
     */
    this.timeStamp = window.performance && window.performance.now ?
        window.performance.now() : Date.now();

    /** @const {string} */
    this.type = type;

    /** @const {boolean} */
    this.isTrusted = false;

    /** @type {EventTarget} */
    this.currentTarget = null;

    /** @type {EventTarget} */
    this.target = null;

    /**
     * Non-standard property read by FakeEventTarget to stop processing
     * listeners.
     * @type {boolean}
     */
    this.stopped = false;
  }
@param {string} type
@param {Map<string, Object>=} dict