Search code examples
typescriptopenlayers

Openlayers, infer Feature type from FeatureLike


Modifying a feature emits the following events.

import { ModifyEvent } from "ol/interaction/Modify";

type DrawToolEvent {
  type: string
  me: ModifyEvent
  layer: VectorLayer<any>
}

And the logic below is executed on the side that subscribes to the DrawToolEvent.

this.drawTool.drawEvent.subscribe((e: DrawToolEvent) => {
  if(e.type === 'A') {
    // ...
  } else if(e.type === 'B') {
    // ...
  } else if (e.type === 'C') {
    const featureLike = e.me.features.getArray()[0]
    const clone = featureLike.clone()  // error: Property 'clone' does not exist on type 'FeatureLike'. Property 'clone' does not exist on type 'RenderFeature'.

    // ...
  }
})

Problem

enter image description here
TypeScript says that e.me.features.getArray()[0] returns FeatureLike type, but it actually returns Feature type when i check through the console. And it actually works the ways below.

// works.
// @ts-ignore
const clone = e.me.features.getArray()[0].clone()

// works.
const clone = (e.me.features.getArray()[0] as Feature<Point>).clone()

// not works.
const clone = e.me.features.getArray()[0].clone()

Question

I don't want to change or ignore the type every time. Is there a better way to convert type FeatureLike into Feature<T>?

ol v6.9.0


Solution

  • I had the same problem when handling the single click event on map. The target in callback params is FeatureLike[], but I needed Feature to respond the click event.

    I cannot find a appropriate way to convert type FeatureLike to Feature as well. Then I check up the properties and methods that a FeatureLike provides. They are as the following

    enter image description here

    With those methods, I created new Feature to meet my needs. The getGeometry() returns Geometry | RenderFeature | undefined, which means extra actions requires when create new feature. But it's nothing complex but to force assert the type as Geometry. It is works for my case because there aren't many types of objects on the map. More complex use case may require more logic to guard the feature creation step. The code are as below.

    ...
            if (targetFeature.getGeometry()) {
                setActiveFeature(
                  new Feature({
                    geometry: targetFeature.getGeometry() as Geometry,
                    ...targetFeature.getProperties(),
                  }),
                  false
                );
              }
    ...
    

    It is not the best practice, it is one can solve my problem though. You can refer to this and hopefully it can give you some inspiration to find the better work around.