Mahier
Mahier

Reputation: 113

I can't figure out how to add Typescript to my React useState hooks, what am I doing wrong?

I've been having a lot of problems adding Typescript to my React code, specifically with useSate hooks.

I've spent the past few days reviewing how to fix this but I'm unsure what needs to be passed into the hooks. Should I be creating a seperate .ts file to store what I expect in the hooks? When I scroll over the underlined errors, it keeps showing errors like:

Argument of type 'Map' is not assignable to parameter of type 'SetStateAction'. Type 'Map' provides no match for the signature '(prevState: undefined): undefined'.

or

Property 'features' does not exist on type '{ children?: ReactNode; }'.`

I've included my code to give a better perspective and left in the comments from the source I'm using.

import { FC } from "react";
import { useState, useEffect, useRef } from "react";
import "./mapwrapper.css";

// openlayers
import Map from "ol/Map";
import View from "ol/View";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import XYZ from "ol/source/XYZ"; //here...

import { fromLonLat } from "ol/proj";

const Home: FC<{}> = (props) => {
  // set intial state
  const [map, setMap] = useState();
  const [featuresLayer, setFeaturesLayer] = useState();

  // pull refs
  const mapElement = useRef<HTMLDivElement>(null);

  // create state ref that can be accessed in OpenLayers onclick callback function
  //  https://stackoverflow.com/a/60643670
  const mapRef = useRef<{}>();
  mapRef.current = map;

  // initialize map on first render - logic formerly put into componentDidMount
  useEffect(() => {
    // create and add vector source layer
    const initalFeaturesLayer = new VectorLayer({
      source: new VectorSource(),
    });

    const seoul = [126.97794, 37.56629];
    const seoulWebMercator = fromLonLat(seoul);

    // create map
    const initialMap = new Map({
      target: mapElement.current!,
      layers: [

        // Google Maps Terrain
        new TileLayer({
          source: new XYZ({
            url: "http://mt0.google.com/vt/lyrs=m&hl=en&x={x}&y={y}&z={z}",
          }),
        }),

        initalFeaturesLayer,
      ],
      view: new View({
        projection: "EPSG:3857",
        center: seoulWebMercator,
        zoom: 16,
      }),
      controls: [],
    });

    // save map and vector layer references to state
    setMap(initialMap);
    setFeaturesLayer(initalFeaturesLayer);
  }, []);

  // update map if features prop changes - logic formerly put into componentDidUpdate
  useEffect(() => {
    if (props.features.length) {
      // may be null on first render

      // set features to map
      featuresLayer.setSource(
        new VectorSource({
          features: props.features, // make sure features is an array
        })
      );

      // fit map to feature extent (with 100px of padding)
      map.getView().fit(featuresLayer.getSource().getExtent(), {
        padding: [100, 100, 100, 100],
      });
    }
  }, [props.features, featuresLayer, map]);


  return (
    <div>
      <div ref={mapElement} className="map-container"></div>

    </div>
  );
};

export default Home;

Upvotes: 2

Views: 6371

Answers (2)

Mic Fung
Mic Fung

Reputation: 5692

For the map problem, you should provide the type explicitly

const [map, setMap] = useState<Map>();

For feature and featureLayer problem, you should provide the props type

type HomeProps = { features: any[] };

const Home: FC<HomeProps> = (props) => {

 const [map, setMap] = useState<Map>();
 const [featuresLayer, setFeaturesLayer] = useState<
    VectorLayer<VectorSource<Geometry>>
 >();


 ...

 useEffect(() => {
    if (props.features?.length && featuresLayer) {
    ...
    }
 }, [props.features, featuresLayer, map]);
  
}

Here is the codesandbox for demo

Upvotes: 2

yqlim
yqlim

Reputation: 7118

In TypeScript you need to declare all types, including all properties inside an object type.

From the error messages you provided, the two errors are because you did not declare the correct type.

Argument of type 'Map' is not assignable to parameter of type 'SetStateAction'. Type 'Map' provides no match for the signature '(prevState: undefined): undefined'.

This error is because you did not declare a type for useState, so it is defaulted to undefined. You can easily fix it by doing something like this:

// You should substitute `any` type to a more appropriate type.
const [map, setMap] = useState<Map<any, any>>();

Property 'features' does not exist on type '{ children?: ReactNode; }'.`

This error is because you did not declare the properties required in the type of component props.

type HomeProps = {
  // You should substitute `any` type to a more appropriate type.
  features: any;
};

const Home: FC<HomeProps> = (props) => {
  ...
}

There are probably more similar errors where you did not declare the types properly. All you need to do is to declare them.

Upvotes: 0

Related Questions