8

I'm attempting to implement a map component with leaflet and other leaflet plugins. The issue is other plugins don't work from TypeScript for some reason.

For example I'm unable to compile code with leaflet-draw plugin and getting the error:

Property 'Draw' does not exist on type 'typeof Control'

mapbox.component.ts

import { DataService } from "../data-service.service";
import { Component, OnInit } from '@angular/core';


import * as $ from 'jquery';
/// <reference types="leaflet" />
/// <reference types="leaflet-draw" />

declare var require: any


@Component({
    selector: 'app-mapbox',
    templateUrl: './mapbox.component.html',
    styleUrls: ['./mapbox.component.css']
})

export class MapboxComponent implements OnInit {

    constructor(private dataService: DataService) { }
    // helper flags
    map: L.Map = null;
    aggreagte: boolean = false;

    ngOnInit() {
        // Prepare map
        this.map = L.map('resultmap').setView([51.505, -0.09], 1);
        //
        L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
            attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
            maxZoom: 18,
            id: 'mapbox.streets',
            accessToken: '...'
        }).addTo(this.map);

        var drawnItems = L.featureGroup();
        this.map.addLayer(drawnItems);
        var control = new L.Control.Draw();
        ...

angular-cli.json

"apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.json",
      "prefix": "app",
      "styles": [
        "styles.css",
        "../node_modules/leaflet/dist/leaflet.css",
        "../node_modules/leaflet-markercluster/MarkerCluster.css",
        "../node_modules/leaflet-draw/dist/leaflet.draw.css"
      ],
      "scripts": [
        "../node_modules/jquery/dist/jquery.min.js",
        "../node_modules/leaflet/dist/leaflet.js",
        "../node_modules/leaflet-markercluster/leaflet.markercluster.js",
        "../node_modules/leaflet-draw/dist/leaflet.draw.js",
        "../node_modules/chart.js/dist/Chart.bundle.min.js"
      ],
      "environments": {
        "source": "environments/environment.ts",
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ]
...

tsconfig.json

"compilerOptions": {
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "../dist/out-tsc-e2e",
    "sourceMap": true,
    "target": "es5",
    "files":[
      "../node_modules/@types/leaflet-draw/index.d.ts"
    ],
    "typeRoots": [
      "../node_modules/@types"
    ],
    "types":[
      "jquery",
      "leaflet",
      "leaflet-draw",
      "leaflet-markercluster"
    ]
  }
aclowkay
  • 3,577
  • 5
  • 35
  • 66
  • I find that errors such as "Namespace '"...leaflet/index"' has no exported member 'DrawOptions'" and "Property 'Draw' does not exist on type 'typeof import("...@types/leaflet/index")' appear after upgrading `@types/leaflet` from version 1.5.17 to 1.5.19 or higher. The newest `@types/leaflet-draw` (version 1.0.5) otherwise works okay. `import 'leaflet-draw';` is required. – Qwertie Aug 03 '22 at 09:26

4 Answers4

7

I solved the issue by importing leaflet-draw

import 'leaflet-draw';

Not sure why it wasn't import by tsconfig, but yay it works!

aclowkay
  • 3,577
  • 5
  • 35
  • 66
  • 1
    That's because you are importing a type definition file. This does not compile to actual JS but is just a tool so you can code type safe – Poul Kruijt Mar 06 '17 at 08:51
  • @PierreDuc Oh. Any references for further reading? I want to understand better how it works. I tried the same trick for leaflet-markercluster - no luck. – aclowkay Mar 06 '17 at 09:25
  • 2
    @aclokay Google _Angular_ and _TypeScript_ relation. There should be enough material for you to understand the issue you have. For starters: https://github.com/angular/angular-cli/wiki/stories-third-party-lib – Yuri Mar 06 '17 at 14:51
  • Where did you put import 'leaflet-draw'; in the app.module.ts or in the component in which you are creating the map? – ackuser Mar 15 '17 at 08:19
  • @ackuser the component – aclowkay Mar 15 '17 at 08:28
  • 4
    I have exactly the same example but still not get it working. I am receiving L.Control.Draw is not a constructor so it doesn't get the typescript definition and I have no idea why. tsc -v Version 2.2.1 ng -v @angular/cli: 1.0.0-rc.0 node: 6.2.0 os: linux x64 I have no idea why, neither with leaflet-markercluster. Could you share your code or put a complete example? – ackuser Mar 15 '17 at 08:42
  • @ackuser The example is complete in terms of things related to the typescript and angular stuff. I would suggest opening a new topic and putting your project configuration. The issue might be for different reasons – aclowkay Mar 15 '17 at 15:24
5

Thanks @aclokay for the insight. I'd complete this answer by adding that you musn't forget to change the standard leaflet import as well. For example :

// import * as L from 'leaflet';  
// --> Doesn't work : Property 'Draw' does not exist on type 'typeof Control'.
declare const L: any; // --> Works
import 'leaflet-draw';

export function drawPlugin(map: any) {
  const drawnItems = L.featureGroup().addTo(map);

  const drawControl = new L.Control.Draw({
    edit: {
      featureGroup: drawnItems,
    },
    draw: {
      polygon: false,
      polyline: false,
      marker: false,
      circlemarker: false
    }
  });
  map.addControl(drawControl);

  map.on(L.Draw.Event.CREATED, function (event) {
    const layer = event.layer;

    drawnItems.addLayer(layer);
  });
}
Alex Beugnet
  • 4,003
  • 4
  • 23
  • 40
  • For a better understanding, a full example using Angular-CLI and the leaflet library and its plugins is available here : https://github.com/consbio/Leaflet.ZoomBox/issues/15 – Alex Beugnet Sep 05 '17 at 18:18
0

You should instead add this library

npm install --save-dev @types/leaflet-draw

Installing this fixed the issue for me as well as providing types for the draw library rather than making everything unknown.

https://www.npmjs.com/package/@types/leaflet-draw

Lindstrom
  • 795
  • 1
  • 5
  • 10
-2
npm i --save-dev @types/leaflet-draw

import "leaflet-draw";
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • 2
    [A code-only answer is not high quality](//meta.stackoverflow.com/questions/392712/explaining-entirely-code-based-answers). While this code may be useful, you can improve it by saying why it works, how it works, when it should be used, and what its limitations are. Please [edit] your answer to include explanation and link to relevant documentation. – Stephen Ostermiller Apr 25 '22 at 15:04