typescriptvue.jsvuejs3mapbox-gl-jsmaplibre-gl

VueJS (TypeScript) component with mapBox


I'm trying to integrate a map from MapBox (or maplibre) within a VueJS component.

The thing is, I need to declare my map in the data part, but the div that will contain my map is not initialized yet. So I have to instantiate my Map inside the mounted() block.

I've tried this:

<template>
  <div id="mapContainer" class="basemap"></div>
</template>

<script lang="ts">
import maplibregl from "maplibre-gl";
import { defineComponent } from "vue";

export default defineComponent({
  name: "BaseMap",
  data() {
    return {
      map: null satisfies maplibregl.Map | null,
    };
  },
  mounted() {
    this.map = new maplibregl.Map({
      container: "mapContainer",
      style:
        `https://api.maptiler.com/maps/voyager-v2/style.json?key=` +
        import.meta.env.VITE_MAP_TOKEN,
      center: [15, 56.5],
      zoom: 3.6,
    });
  },
  methods(): {},
});
</script>

But I'm getting TS2322: Type 'Map' is not assignable to type 'null'. and TS2531: Object is possibly 'null'. on all calls on this.map.

Is there an easy way to force to type of this.map or do this in a cleaner way ?

Thanks


Solution

  • satisfies won't work. It will set the narrowest type it can set, in this case, the type of map is set to null.

    You can see that error on this simple TypeScript example

    let y = null satisfies number | null;
    y = 123; // error Type '123' is not assignable to type `null`
    

    I would recommend using an interface to define all the types of the properties in the data

    <template>
      <div id="mapContainer" class="basemap"></div>
    </template>
    
    <script lang="ts">
    import maplibregl from "maplibre-gl";
    import { defineComponent } from "vue";
    
    interface Data {
        map: maplibregl.Map | null;
    }
    
    export default defineComponent<Data>({
      name: "BaseMap",
      data() {
        return {
          map: null,
        };
      },
      mounted() {
        this.map = new maplibregl.Map({
          container: "mapContainer",
          style:
            `https://api.maptiler.com/maps/voyager-v2/style.json?key=` +
            import.meta.env.VITE_MAP_TOKEN,
          center: [15, 56.5],
          zoom: 3.6,
        });
      },
      methods(): {},
    });
    </script>
    

    For the TS2531: Object is possibly 'null'. error you need to use either optional chaining (?.) or non-null assertion (!.) e.g.

    this.map?.moveLayer('id', 'beforeId');
    this.map!.moveLayer('id', 'beforeId');