首页 > 解决方案 > 在 React 和 Typescript 中为传单搜索插件分配类型

问题描述

我有以下问题:在我的项目中,我安装了传单库来显示带有图像(建筑物的平面图)的地图,并且每张地图都有一个Point,它是一个GeoJson Point,它象征着该特定楼层内的扇区。

由于每一层都有很多点,所以我搜索了传单插件,其中一个满足了我的期望,传单搜索。但碰巧 TypeScript 无法识别它的类型,特别是在 L.Control.Search() 中,声称 Control 没有 typeof 'Search'。

尝试安装一些

npm i --save-dev @types/leaflet-search

但在 npm 存储库中找不到它。有趣的是,运行npm run dev它可以完美运行,按照我需要的方式搜索点,如下图所示:

Rodando 在 npm run dev 上

但是在使用时npm run build,它会给出这种类型的“搜索”错误。我将向您展示代码:

组件/Leaflet.tsx

import L, { LatLngBounds } from 'leaflet';
import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css';
import 'leaflet-defaulticon-compatibility';

//https://www.npmjs.com/package/leaflet-fullscreen
import 'leaflet-fullscreen';
import 'leaflet-fullscreen/dist/leaflet.fullscreen.css';

//https://www.npmjs.com/package/leaflet-search
import 'leaflet-search/src/leaflet-search.js';
import 'leaflet-search/src/leaflet-search.css';

import { useCallback, useEffect, useRef } from 'react';

import { LeafletProps } from './type';

const style = { border: '1px black solid', width: '100%', height: '500px' };

export default function Leaflet({
  id,
  cover,
  sector,
  floorBuild,
  buildName,
}: LeafletProps) {
  const mapContainerRef = useRef(null);

  const container = document.getElementById(`${id}`);
  if (container) {
    container.remove();
  }

  //Função de inicio do component
  const loadInitial = useCallback(
    (map, cover, geoJson, floorBuild, buildName) => {
      let internalFloor = '';
      switch (floorBuild) {
        case 0:
          internalFloor = 'Térreo';
          break;
        case 1:
          internalFloor = '1ª andar';
          break;
        case 2:
          internalFloor = '2ª andar';
          break;
        case 3:
          internalFloor = '3ª andar';
          break;
        case 4:
          internalFloor = '4ª andar';
          break;
        default:
          internalFloor = '';
      }

      const bounds = new LatLngBounds([0, 0], [cover.height, cover.width]);

      L.imageOverlay(`${cover.srcImg}`, bounds).addTo(map);

      map.fitBounds(bounds);

      map.setView([cover.height / 2, cover.width / 2], -2);

      const featuresLayer = L.geoJSON(geoJson, {
        onEachFeature: (feature, layer) => {
          let popupContent = ``;

          if (feature.properties && feature.properties.name) {
            popupContent += `<p>${feature.properties.name}</p>`;
          }

          layer.bindPopup(popupContent);
        },

        attribution: `&copy; ${buildName} - ${internalFloor}`,
      });

      map.addLayer(featuresLayer);

      //Apenas para coletar os dados
      function onMapClick(e) {
        console.log(e.latlng.toString());
      }

      map.on('click', onMapClick);

      //Search
      // eslint-disable-next-line no-use-before-define
      const searchControl = new L.Control.Search({
        layer: featuresLayer,
        propertyName: 'name',
        marker: false,
        autoType: false,
      });

      searchControl
        .on('search:locationfound', function (e) {

          if (e.layer._popup) e.layer.openPopup();
        })
        .on('search:collapsed', function (e) {
          featuresLayer.eachLayer(function (layer) {
            //restore feature color
            featuresLayer.resetStyle(layer);
          });
        });

      map.addControl(searchControl);
    },
    [],
  );

  useEffect(() => {
    const map = L.map(mapContainerRef.current, {
      crs: L.CRS.Simple,
      zoom: 5,
      minZoom: -3,
      maxZoom: 5,
      fullscreenControl: true,
    });

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const geoJson: GeoJSON.FeatureCollection<any> = {
      type: 'FeatureCollection',
      features: [],
    };

    floorBuild++;

    sector.map((s) => {
      if (s.mapLat != null && s.mapLon != null) {
        if (floorBuild === s.floor.floorNumber) {
          const item: GeoJSON.Feature = {
            type: 'Feature',
            properties: {
              name: `${s.name} - ${s.initials}`,
            },
            geometry: {
              type: 'Point',
              coordinates: [s.mapLat, s.mapLon],
            },
          };
          geoJson.features.push(item);
        }
      }
    });

    loadInitial(map, cover, geoJson, floorBuild, buildName);

    // unmount map function
    return () => {
      map.off();
      map.remove();
    };
  }, [loadInitial, sector, cover, floorBuild, buildName]);

  return (
    <>
      <div
        id={id}
        className="maps-Builds"
        ref={mapContainerRef}
        style={style}
      ></div>
      <br />
    </>
  );
}

包.json

{
  "name": "faqs-bancada",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "debug": "NODE_OPTIONS='--inspect' next dev",
    "build": "next build",
    "export": "next export",
    "start": "next start",
    "storybook": "start-storybook -p 6006 -s ./public",
    "build-storybook": "build-storybook",
    "test": "jest",
    "deploy-static": "npm run build && npm run export",
    "lint": "eslint src --max-warnings=0",
    "lint-staged": "lint-staged",
    "prepare": "husky install"
  },
  "dependencies": {
    "@styled-icons/boxicons-logos": "^10.37.0",
    "@styled-icons/boxicons-regular": "^10.37.0",
    "@styled-icons/evaicons-outline": "^10.34.0",
    "@styled-icons/material-outlined": "^10.28.0",
    "anchor-js": "^4.3.1",
    "bootstrap": "^4.6.0",
    "d3-mitch-tree": "^1.1.2",
    "graphql": "^15.6.1",
    "graphql-request": "^3.5.0",
    "leaflet": "^1.7.1",
    "leaflet-defaulticon-compatibility": "^0.1.1",
    "leaflet-fullscreen": "^1.0.2",
    "leaflet-search": "^3.0.2",
    "next": "^11.1.0",
    "prop-types": "^15.7.2",
    "react": "17.0.1",
    "react-bootstrap": "^1.6.4",
    "react-data-table-component": "^7.4.4",
    "react-data-table-component-extensions": "^1.5.2",
    "react-data-table-component-with-filter": "^7.0.1",
    "react-dom": "17.0.1",
    "react-leaflet": "^3.2.2",
    "styled-components": "^5.2.1"
  },
  "devDependencies": {
    "@babel/core": "^7.15.8",
    "@storybook/addon-actions": "^6.3.11",
    "@storybook/addon-docs": "^6.3.11",
    "@storybook/addon-essentials": "^6.3.11",
    "@storybook/addon-links": "^6.3.11",
    "@storybook/react": "^6.3.11",
    "@testing-library/jest-dom": "^5.11.9",
    "@testing-library/react": "^11.2.5",
    "@testing-library/user-event": "^13.3.0",
    "@types/anchor-js": "^4.2.1",
    "@types/express": "^4.17.13",
    "@types/leaflet": "^1.7.5",
    "@types/leaflet-fullscreen": "^1.0.5",
    "@types/node": "^14.17.22",
    "@types/react": "^17.0.29",
    "@types/styled-components": "^5.1.15",
    "@typescript-eslint/eslint-plugin": "^4.33.0",
    "@typescript-eslint/parser": "^4.33.0",
    "babel-loader": "^8.2.2",
    "babel-plugin-styled-components": "^1.12.0",
    "eslint": "^7.22.0",
    "eslint-config-prettier": "^8.1.0",
    "eslint-plugin-prettier": "^3.3.1",
    "eslint-plugin-react": "^7.26.1",
    "eslint-plugin-react-hooks": "^4.2.0",
    "husky": "^5.1.3",
    "jest": "^26.6.3",
    "jest-styled-components": "^7.0.3",
    "lint-staged": "^10.5.4",
    "msw": "^0.35.0",
    "node-fetch": "^3.0.0",
    "prettier": "^2.2.1",
    "storybook-addon-next-router": "^3.0.8",
    "typescript": "^4.4.4"
  },
  "lint-staged": {
    "src/**/*": [
      "npm run lint -- --fix"
    ]
  }
}

构建时出现此错误:

PS D:\JSProjects\faqs-bancada> npm run deploy-static

> faqs-bancada@0.1.0 deploy-static D:\JSProjects\faqs-bancada
> npm run build && npm run export


> faqs-bancada@0.1.0 build D:\JSProjects\faqs-bancada
> next build

info  - Using webpack 5. Reason: Enabled by default https://nextjs.org/docs/messages/webpack5
Failed to compile.

./src/components/Leaflet/index.tsx:92:43
Type error: Property 'Search' does not exist on type 'typeof Control'.

  90 |       //Search
  91 |       // eslint-disable-next-line no-use-before-define
> 92 |       const searchControl = new L.Control.Search({
     |                                           ^
  93 |         layer: featuresLayer,
  94 |         propertyName: 'name',
  95 |         marker: false,
info  - Checking validity of types .npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! faqs-bancada@0.1.0 build: `next build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the faqs-bancada@0.1.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\paulo\AppData\Roaming\npm-cache\_logs\2021-10-16T13_38_12_506Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! faqs-bancada@0.1.0 deploy-static: `npm run build && npm run export`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the faqs-bancada@0.1.0 deploy-static script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\paulo\AppData\Roaming\npm-cache\_logs\2021-10-16T13_38_12_544Z-debug.log

错误始终是:类型错误:“typeof Control”类型上不存在属性“搜索”

我尝试寻找一些 eslint 评论,例如eslint-disable-next-line no-use-before-define,但效果不佳。

我的问题是:如何为 Search 分配一个类型,以便我可以正常构建项目?如何解决此错误?

标签: reactjstypescriptnpmleafleteslint

解决方案


推荐阅读