Search code examples
reactjstypescriptleafletreact-leaflet

Property 'context' is missing in type '{ instance: any; }' but required in type 'LeafletElement<Evented, any>'


I'm trying to execute this react-leaflet example: https://react-leaflet.js.org/docs/example-react-control/

This is the code:

import * as React from 'react';

import * as leaflet from 'leaflet'
import { MapContainer, TileLayer, Marker, Popup, useMapEvent, useMap, Rectangle } from 'react-leaflet'
import { useEventHandlers } from '@react-leaflet/core'


import "leaflet/dist/leaflet.css"
import "leaflet/dist/images/marker-shadow.png"

import Box from '@mui/material/Box'

export default function Mapping(props) {

  // Classes used by Leaflet to position controls
  const POSITION_CLASSES = {
    bottomleft: 'leaflet-bottom leaflet-left',
    bottomright: 'leaflet-bottom leaflet-right',
    topleft: 'leaflet-top leaflet-left',
    topright: 'leaflet-top leaflet-right',
  }

  const BOUNDS_STYLE = { weight: 1 }

  function MinimapBounds({ parentMap, zoom }) {
    const minimap = useMap()

    // Clicking a point on the minimap sets the parent's map center
    const onClick = React.useCallback(
      (e) => {
        parentMap.setView(e.latlng, parentMap.getZoom())
      },
      [parentMap],
    )
    useMapEvent('click', onClick)

    // Keep track of bounds in state to trigger renders
    const [bounds, setBounds] = React.useState(parentMap.getBounds())
    const onChange = React.useCallback(() => {
      setBounds(parentMap.getBounds())
      // Update the minimap's view to match the parent map's center and zoom
      minimap.setView(parentMap.getCenter(), zoom)
    }, [minimap, parentMap, zoom])

    // Listen to events on the parent map
    const handlers = React.useMemo(() => ({ move: onChange, zoom: onChange }), [])
    useEventHandlers({ instance: parentMap }, handlers)

    return <Rectangle bounds={bounds} pathOptions={BOUNDS_STYLE} />
  }

  function MinimapControl({ position, zoom }) {
    const parentMap = useMap()
    const mapZoom = zoom || 0

    // Memoize the minimap so it's not affected by position changes
    const minimap = React.useMemo(
      () => (
        <MapContainer
          style={{ height: 80, width: 80 }}
          center={parentMap.getCenter()}
          zoom={mapZoom}
          dragging={false}
          doubleClickZoom={false}
          scrollWheelZoom={false}
          attributionControl={false}
          zoomControl={false}>
          <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
          <MinimapBounds parentMap={parentMap} zoom={mapZoom} />
        </MapContainer>
      ),
      [],
    )

    const positionClass =
      (position && POSITION_CLASSES[position]) || POSITION_CLASSES.topright
    return (
      <div className={positionClass}>
        <div className="leaflet-control leaflet-bar">{minimap}</div>
      </div>
    )
  }

  return (
    <div>
      <h3>Map</h3>

      <div id="map">

        <MapContainer
          center={[51.505, -0.09]}
          zoom={13}
          scrollWheelZoom={false}
          style={{ height: '100vh', width: '100wh' }}
        >

          <TileLayer
            attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          />

          <Marker position={[51.505, -0.09]}>
            <Popup>
              A pretty CSS3 popup. <br /> Easily customizable.
            </Popup>
          </Marker>
        </MapContainer>

      </div>


    </div>
  )

I'm getting this error message:

src/app_D/components/mapVisualize/maps.tsx:54:22 - error TS2345: Argument of type '{ instance: any; }' is not assignable to parameter of type 'LeafletElement<Evented, any>'.
  Property 'context' is missing in type '{ instance: any; }' but required in type 'LeafletElement<Evented, any>'.

54     useEventHandlers({ instance: parentMap }, handlers)
                        ~~~~~~~~~~~~~~~~~~~~~~~

  node_modules/@react-leaflet/core/types/element.d.ts:5:5
    5     context: LeafletContextInterface;
          ~~~~~~~
    'context' is declared here.

src/app_D/components/mapVisualize/maps.tsx:104:10 - error TS2741: Property 'zoom' is missing in type '{ position: string; }' but required in type '{ position: any; zoom: any; }'.

104         <MinimapControl position="topright" />
         ~~~~~~~~~~~~~~

If I "convert" the file to a javascript file: maps.tsx -> maps.js , then it works fine:

enter image description here

So it must be something related to typescript types

Other info:

"@types/leaflet": "^1.7.8"
"leaflet": "^1.7.1"
"webpack": "^5.23.0"
"react": "^17.0.2"
"react-leaflet": "^3.2.5"
node: v16.13.0
O.S.: Ubuntu 20.04 Desktop

How to solve the problem?


Solution

  • The definition of LeafletElement in element.d.ts is:

    export interface LeafletElement<T, C = any> {
        instance: T;
        context: LeafletContextInterface;
        container?: C | null;
    }
    

    Which indicates that context is a required element. But the usage of useEventHandlers in the examples for react-leaflet seem to indicate that context is not required. I filed a bug report here.

    You can workaround the issue with useLeafletContext and then using it in the call to useEventHandlers:

      const context = useLeafletContext();
    
      // ... rest of code removed for brevity
    
      useEventHandlers({instance: parentMap, context}, handlers);