Improve Collection type-safety
This commit is contained in:
@@ -18,11 +18,12 @@ const Property = {
|
||||
* @classdesc
|
||||
* Events emitted by {@link module:ol/Collection~Collection} instances are instances of this
|
||||
* type.
|
||||
* @template T
|
||||
*/
|
||||
export class CollectionEvent extends Event {
|
||||
/**
|
||||
* @param {import("./CollectionEventType.js").default} type Type.
|
||||
* @param {*} element Element.
|
||||
* @param {T} element Element.
|
||||
* @param {number} index The index of the added or removed element.
|
||||
*/
|
||||
constructor(type, element, index) {
|
||||
@@ -30,7 +31,7 @@ export class CollectionEvent extends Event {
|
||||
|
||||
/**
|
||||
* The element that is added to or removed from the collection.
|
||||
* @type {*}
|
||||
* @type {T}
|
||||
* @api
|
||||
*/
|
||||
this.element = element;
|
||||
@@ -45,10 +46,11 @@ export class CollectionEvent extends Event {
|
||||
}
|
||||
|
||||
/***
|
||||
* @template T
|
||||
* @template Return
|
||||
* @typedef {import("./Observable").OnSignature<import("./Observable").EventTypes, import("./events/Event.js").default, Return> &
|
||||
* import("./Observable").OnSignature<import("./ObjectEventType").Types|'change:length', import("./Object").ObjectEvent, Return> &
|
||||
* import("./Observable").OnSignature<'add'|'remove', CollectionEvent, Return> &
|
||||
* import("./Observable").OnSignature<'add'|'remove', CollectionEvent<T>, Return> &
|
||||
* import("./Observable").CombinedOnSignature<import("./Observable").EventTypes|import("./ObjectEventType").Types|
|
||||
* 'change:length'|'add'|'remove',Return>} CollectionOnSignature
|
||||
*/
|
||||
@@ -81,17 +83,17 @@ class Collection extends BaseObject {
|
||||
super();
|
||||
|
||||
/***
|
||||
* @type {CollectionOnSignature<import("./events").EventsKey>}
|
||||
* @type {CollectionOnSignature<T, import("./events").EventsKey>}
|
||||
*/
|
||||
this.on;
|
||||
|
||||
/***
|
||||
* @type {CollectionOnSignature<import("./events").EventsKey>}
|
||||
* @type {CollectionOnSignature<T, import("./events").EventsKey>}
|
||||
*/
|
||||
this.once;
|
||||
|
||||
/***
|
||||
* @type {CollectionOnSignature<void>}
|
||||
* @type {CollectionOnSignature<T, void>}
|
||||
*/
|
||||
this.un;
|
||||
|
||||
@@ -264,7 +266,9 @@ class Collection extends BaseObject {
|
||||
this.array_.splice(index, 1);
|
||||
this.updateLength_();
|
||||
this.dispatchEvent(
|
||||
/** @type {CollectionEvent<T>} */ (
|
||||
new CollectionEvent(CollectionEventType.REMOVE, prev, index)
|
||||
)
|
||||
);
|
||||
return prev;
|
||||
}
|
||||
@@ -290,10 +294,14 @@ class Collection extends BaseObject {
|
||||
const prev = this.array_[index];
|
||||
this.array_[index] = elem;
|
||||
this.dispatchEvent(
|
||||
/** @type {CollectionEvent<T>} */ (
|
||||
new CollectionEvent(CollectionEventType.REMOVE, prev, index)
|
||||
)
|
||||
);
|
||||
this.dispatchEvent(
|
||||
/** @type {CollectionEvent<T>} */ (
|
||||
new CollectionEvent(CollectionEventType.ADD, elem, index)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -439,7 +439,7 @@ class PluggableMap extends BaseObject {
|
||||
this.controls.addEventListener(
|
||||
CollectionEventType.ADD,
|
||||
/**
|
||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
||||
* @param {import("./Collection.js").CollectionEvent<import("./control/Control.js").default>} event CollectionEvent
|
||||
*/
|
||||
function (event) {
|
||||
event.element.setMap(this);
|
||||
@@ -449,7 +449,7 @@ class PluggableMap extends BaseObject {
|
||||
this.controls.addEventListener(
|
||||
CollectionEventType.REMOVE,
|
||||
/**
|
||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
||||
* @param {import("./Collection.js").CollectionEvent<import("./control/Control.js").default>} event CollectionEvent.
|
||||
*/
|
||||
function (event) {
|
||||
event.element.setMap(null);
|
||||
@@ -459,7 +459,7 @@ class PluggableMap extends BaseObject {
|
||||
this.interactions.addEventListener(
|
||||
CollectionEventType.ADD,
|
||||
/**
|
||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
||||
* @param {import("./Collection.js").CollectionEvent<import("./interaction/Interaction.js").default>} event CollectionEvent.
|
||||
*/
|
||||
function (event) {
|
||||
event.element.setMap(this);
|
||||
@@ -469,7 +469,7 @@ class PluggableMap extends BaseObject {
|
||||
this.interactions.addEventListener(
|
||||
CollectionEventType.REMOVE,
|
||||
/**
|
||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
||||
* @param {import("./Collection.js").CollectionEvent<import("./interaction/Interaction.js").default>} event CollectionEvent.
|
||||
*/
|
||||
function (event) {
|
||||
event.element.setMap(null);
|
||||
@@ -479,25 +479,20 @@ class PluggableMap extends BaseObject {
|
||||
this.overlays_.addEventListener(
|
||||
CollectionEventType.ADD,
|
||||
/**
|
||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
||||
* @param {import("./Collection.js").CollectionEvent<import("./Overlay.js").default>} event CollectionEvent.
|
||||
*/
|
||||
function (event) {
|
||||
this.addOverlayInternal_(
|
||||
/** @type {import("./Overlay.js").default} */ (event.element)
|
||||
);
|
||||
this.addOverlayInternal_(event.element);
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
this.overlays_.addEventListener(
|
||||
CollectionEventType.REMOVE,
|
||||
/**
|
||||
* @param {import("./Collection.js").CollectionEvent} event CollectionEvent.
|
||||
* @param {import("./Collection.js").CollectionEvent<import("./Overlay.js").default>} event CollectionEvent.
|
||||
*/
|
||||
function (event) {
|
||||
const overlay = /** @type {import("./Overlay.js").default} */ (
|
||||
event.element
|
||||
);
|
||||
const id = overlay.getId();
|
||||
const id = event.element.getId();
|
||||
if (id !== undefined) {
|
||||
delete this.overlayIdIndex_[id.toString()];
|
||||
}
|
||||
@@ -1709,7 +1704,12 @@ function createOptionsInternal(options) {
|
||||
options.layers &&
|
||||
typeof (/** @type {?} */ (options.layers).getLayers) === 'function'
|
||||
? /** @type {LayerGroup} */ (options.layers)
|
||||
: new LayerGroup({layers: /** @type {Collection} */ (options.layers)});
|
||||
: new LayerGroup({
|
||||
layers:
|
||||
/** @type {Collection<import("./layer/Base.js").default>|Array<import("./layer/Base.js").default>} */ (
|
||||
options.layers
|
||||
),
|
||||
});
|
||||
values[MapProperty.LAYERGROUP] = layerGroup;
|
||||
|
||||
values[MapProperty.TARGET] = options.target;
|
||||
@@ -1717,6 +1717,7 @@ function createOptionsInternal(options) {
|
||||
values[MapProperty.VIEW] =
|
||||
options.view instanceof View ? options.view : new View();
|
||||
|
||||
/** @type {Collection<import("./control/Control.js").default>} */
|
||||
let controls;
|
||||
if (options.controls !== undefined) {
|
||||
if (Array.isArray(options.controls)) {
|
||||
@@ -1726,10 +1727,11 @@ function createOptionsInternal(options) {
|
||||
typeof (/** @type {?} */ (options.controls).getArray) === 'function',
|
||||
47
|
||||
); // Expected `controls` to be an array or an `import("./Collection.js").Collection`
|
||||
controls = /** @type {Collection} */ (options.controls);
|
||||
controls = options.controls;
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {Collection<import("./interaction/Interaction").default>} */
|
||||
let interactions;
|
||||
if (options.interactions !== undefined) {
|
||||
if (Array.isArray(options.interactions)) {
|
||||
@@ -1740,10 +1742,11 @@ function createOptionsInternal(options) {
|
||||
'function',
|
||||
48
|
||||
); // Expected `interactions` to be an array or an `import("./Collection.js").Collection`
|
||||
interactions = /** @type {Collection} */ (options.interactions);
|
||||
interactions = options.interactions;
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {Collection<import("./Overlay.js").default>} */
|
||||
let overlays;
|
||||
if (options.overlays !== undefined) {
|
||||
if (Array.isArray(options.overlays)) {
|
||||
|
||||
@@ -50,6 +50,7 @@ export {default as ZoomToExtent} from './control/ZoomToExtent.js';
|
||||
export function defaults(opt_options) {
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/** @type {Collection<import("./control/Control.js").default>} */
|
||||
const controls = new Collection();
|
||||
|
||||
const zoomControl = options.zoom !== undefined ? options.zoom : true;
|
||||
|
||||
@@ -84,6 +84,7 @@ export {default as Translate} from './interaction/Translate.js';
|
||||
export function defaults(opt_options) {
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/** @type {Collection<import("./interaction/Interaction.js").default>} */
|
||||
const interactions = new Collection();
|
||||
|
||||
const kinetic = new Kinetic(-0.005, 0.05, 100);
|
||||
|
||||
@@ -361,6 +361,7 @@ class Modify extends PointerInteraction {
|
||||
*/
|
||||
this.hitDetection_ = null;
|
||||
|
||||
/** @type {Collection<Feature>} */
|
||||
let features;
|
||||
if (options.features) {
|
||||
features = options.features;
|
||||
@@ -574,11 +575,11 @@ class Modify extends PointerInteraction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent} evt Event.
|
||||
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||
* @private
|
||||
*/
|
||||
handleFeatureAdd_(evt) {
|
||||
this.addFeature_(/** @type {Feature} */ (evt.element));
|
||||
this.addFeature_(evt.element);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -594,12 +595,11 @@ class Modify extends PointerInteraction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent} evt Event.
|
||||
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||
* @private
|
||||
*/
|
||||
handleFeatureRemove_(evt) {
|
||||
const feature = /** @type {Feature} */ (evt.element);
|
||||
this.removeFeature_(feature);
|
||||
this.removeFeature_(evt.element);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -75,7 +75,7 @@ const SelectEventType = {
|
||||
* @property {boolean} [multi=false] A boolean that determines if the default
|
||||
* behaviour should select only single features or all (overlapping) features at
|
||||
* the clicked map position. The default of `false` means single select.
|
||||
* @property {import("../Collection.js").default<import("../Feature.js").default>} [features]
|
||||
* @property {Collection<Feature>} [features]
|
||||
* Collection where the interaction will place selected features. Optional. If
|
||||
* not set the interaction will create a collection. In any case the collection
|
||||
* used by the interaction is returned by
|
||||
@@ -245,7 +245,7 @@ class Select extends Interaction {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../Collection.js").default}
|
||||
* @type {Collection<Feature>}
|
||||
*/
|
||||
this.features_ = options.features || new Collection();
|
||||
|
||||
@@ -290,7 +290,7 @@ class Select extends Interaction {
|
||||
|
||||
/**
|
||||
* Get the selected features.
|
||||
* @return {import("../Collection.js").default<import("../Feature.js").default>} Features collection.
|
||||
* @return {Collection<Feature>} Features collection.
|
||||
* @api
|
||||
*/
|
||||
getFeatures() {
|
||||
@@ -367,7 +367,7 @@ class Select extends Interaction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent} evt Event.
|
||||
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||
* @private
|
||||
*/
|
||||
addFeature_(evt) {
|
||||
@@ -396,13 +396,12 @@ class Select extends Interaction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent} evt Event.
|
||||
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||
* @private
|
||||
*/
|
||||
removeFeature_(evt) {
|
||||
const feature = evt.element;
|
||||
if (this.style_) {
|
||||
this.restorePreviousStyle_(feature);
|
||||
this.restorePreviousStyle_(evt.element);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +413,7 @@ class Select extends Interaction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Feature.js").default} feature Feature
|
||||
* @param {Feature} feature Feature
|
||||
* @private
|
||||
*/
|
||||
applySelectedStyle_(feature) {
|
||||
@@ -426,7 +425,7 @@ class Select extends Interaction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Feature.js").default} feature Feature
|
||||
* @param {Feature} feature Feature
|
||||
* @private
|
||||
*/
|
||||
restorePreviousStyle_(feature) {
|
||||
@@ -450,7 +449,7 @@ class Select extends Interaction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Feature.js").default} feature Feature.
|
||||
* @param {Feature} feature Feature.
|
||||
* @private
|
||||
*/
|
||||
removeFeatureLayerAssociation_(feature) {
|
||||
@@ -476,12 +475,12 @@ class Select extends Interaction {
|
||||
const features = this.getFeatures();
|
||||
|
||||
/**
|
||||
* @type {Array<import("../Feature.js").default>}
|
||||
* @type {Array<Feature>}
|
||||
*/
|
||||
const deselected = [];
|
||||
|
||||
/**
|
||||
* @type {Array<import("../Feature.js").default>}
|
||||
* @type {Array<Feature>}
|
||||
*/
|
||||
const selected = [];
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ import {listen, unlistenByKey} from '../events.js';
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent} evt Event.
|
||||
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent<import("../Feature.js").default>} evt Event.
|
||||
* @return {import("../Feature.js").default} Feature.
|
||||
*/
|
||||
function getFeatureFromEvent(evt) {
|
||||
@@ -55,11 +55,13 @@ function getFeatureFromEvent(evt) {
|
||||
return /** @type {import("../source/Vector.js").VectorSourceEvent} */ (evt)
|
||||
.feature;
|
||||
} else if (
|
||||
/** @type {import("../Collection.js").CollectionEvent} */ (evt).element
|
||||
/** @type {import("../Collection.js").CollectionEvent<import("../Feature.js").default>} */ (
|
||||
evt
|
||||
).element
|
||||
) {
|
||||
return /** @type {import("../Feature.js").default} */ (
|
||||
/** @type {import("../Collection.js").CollectionEvent} */ (evt).element
|
||||
);
|
||||
return /** @type {import("../Collection.js").CollectionEvent<import("../Feature.js").default>} */ (
|
||||
evt
|
||||
).element;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,6 +263,7 @@ class Snap extends PointerInteraction {
|
||||
* @private
|
||||
*/
|
||||
getFeatures_() {
|
||||
/** @type {import("../Collection.js").default<import("../Feature.js").default>|Array<import("../Feature.js").default>} */
|
||||
let features;
|
||||
if (this.features_) {
|
||||
features = this.features_;
|
||||
@@ -284,7 +287,7 @@ class Snap extends PointerInteraction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent} evt Event.
|
||||
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent<import("../Feature.js").default>} evt Event.
|
||||
* @private
|
||||
*/
|
||||
handleFeatureAdd_(evt) {
|
||||
@@ -293,7 +296,7 @@ class Snap extends PointerInteraction {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent} evt Event.
|
||||
* @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent<import("../Feature.js").default>} evt Event.
|
||||
* @private
|
||||
*/
|
||||
handleFeatureRemove_(evt) {
|
||||
|
||||
@@ -66,7 +66,7 @@ export class GroupEvent extends Event {
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {Array<import("./Base.js").default>|import("../Collection.js").default<import("./Base.js").default>} [layers] Child layers.
|
||||
* @property {Array<import("./Base.js").default>|Collection<import("./Base.js").default>} [layers] Child layers.
|
||||
* @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`.
|
||||
*/
|
||||
|
||||
@@ -214,26 +214,22 @@ class LayerGroup extends BaseLayer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent} collectionEvent CollectionEvent.
|
||||
* @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent.
|
||||
* @private
|
||||
*/
|
||||
handleLayersAdd_(collectionEvent) {
|
||||
const layer = /** @type {import("./Base.js").default} */ (
|
||||
collectionEvent.element
|
||||
);
|
||||
const layer = collectionEvent.element;
|
||||
this.registerLayerListeners_(layer);
|
||||
this.dispatchEvent(new GroupEvent('addlayer', layer));
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent} collectionEvent CollectionEvent.
|
||||
* @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent.
|
||||
* @private
|
||||
*/
|
||||
handleLayersRemove_(collectionEvent) {
|
||||
const layer = /** @type {import("./Base.js").default} */ (
|
||||
collectionEvent.element
|
||||
);
|
||||
const layer = collectionEvent.element;
|
||||
const key = getUid(layer);
|
||||
this.listenerKeys_[key].forEach(unlistenByKey);
|
||||
delete this.listenerKeys_[key];
|
||||
@@ -244,13 +240,13 @@ class LayerGroup extends BaseLayer {
|
||||
/**
|
||||
* Returns the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
|
||||
* in this group.
|
||||
* @return {!import("../Collection.js").default<import("./Base.js").default>} Collection of
|
||||
* @return {!Collection<import("./Base.js").default>} Collection of
|
||||
* {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getLayers() {
|
||||
return /** @type {!import("../Collection.js").default<import("./Base.js").default>} */ (
|
||||
return /** @type {!Collection<import("./Base.js").default>} */ (
|
||||
this.get(Property.LAYERS)
|
||||
);
|
||||
}
|
||||
@@ -258,7 +254,7 @@ class LayerGroup extends BaseLayer {
|
||||
/**
|
||||
* Set the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
|
||||
* in this group.
|
||||
* @param {!import("../Collection.js").default<import("./Base.js").default>} layers Collection of
|
||||
* @param {!Collection<import("./Base.js").default>} layers Collection of
|
||||
* {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
|
||||
* @observable
|
||||
* @api
|
||||
|
||||
@@ -302,10 +302,7 @@ class VectorSource extends Source {
|
||||
/** @type {Array<import("../Feature.js").default<Geometry>>} */
|
||||
let features;
|
||||
if (Array.isArray(options.features)) {
|
||||
features =
|
||||
/** @type {Array<import("../Feature.js").default<Geometry>>} */ (
|
||||
options.features
|
||||
);
|
||||
features = options.features;
|
||||
} else if (options.features) {
|
||||
collection = options.features;
|
||||
features = collection.getArray();
|
||||
@@ -501,16 +498,12 @@ class VectorSource extends Source {
|
||||
collection.addEventListener(
|
||||
CollectionEventType.ADD,
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent} evt The collection event
|
||||
* @param {import("../Collection.js").CollectionEvent<import("../Feature.js").default<Geometry>>} evt The collection event
|
||||
*/
|
||||
function (evt) {
|
||||
if (!modifyingCollection) {
|
||||
modifyingCollection = true;
|
||||
this.addFeature(
|
||||
/** @type {import("../Feature.js").default<Geometry>} */ (
|
||||
evt.element
|
||||
)
|
||||
);
|
||||
this.addFeature(evt.element);
|
||||
modifyingCollection = false;
|
||||
}
|
||||
}.bind(this)
|
||||
@@ -518,16 +511,12 @@ class VectorSource extends Source {
|
||||
collection.addEventListener(
|
||||
CollectionEventType.REMOVE,
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent} evt The collection event
|
||||
* @param {import("../Collection.js").CollectionEvent<import("../Feature.js").default<Geometry>>} evt The collection event
|
||||
*/
|
||||
function (evt) {
|
||||
if (!modifyingCollection) {
|
||||
modifyingCollection = true;
|
||||
this.removeFeature(
|
||||
/** @type {import("../Feature.js").default<Geometry>} */ (
|
||||
evt.element
|
||||
)
|
||||
);
|
||||
this.removeFeature(evt.element);
|
||||
modifyingCollection = false;
|
||||
}
|
||||
}.bind(this)
|
||||
|
||||
Reference in New Issue
Block a user