3

I'm trying to add geoJSON into a react-map-gl map using typescript

here is my code

<Source id="my-data" type="geojson" data={data}>
    <Layer {...layerStyles}/>
</Source>

the data variable is a parsed JSON file so it is an object not

the error I get is

 Overload 1 of 2, '(props: SourceProps | Readonly<SourceProps>): Source', gave the following error.
    Type 'object' is not assignable to type 'string | Feature<Geometry, GeoJsonProperties> | FeatureCollection<Geometry, GeoJsonProperties> | undefined'.
      Type '{}' is missing the following properties from type 'FeatureCollection<Geometry, GeoJsonProperties>': type, features
  Overload 2 of 2, '(props: SourceProps, context: any): Source', gave the following error.
    Type 'object' is not assignable to type 'string | Feature<Geometry, GeoJsonProperties> | FeatureCollection<Geometry, GeoJsonProperties> | undefined'.  TS2769

    123 |             onViewportChange={(nextView:typeof viewport) => setViewport(nextView)}>
    124 |                 {/* GeoJSON */}
  > 125 |                 <Source id="my-data" type="geojson" data={data}>
        |                                                     ^
    126 |                  <Layer {...layerStyles}/>
    127 |                 </Source> 
    128 |                 {markers}

And the type of the data props in the Source component is supposed to be an object as you can see from the documentation https://visgl.github.io/react-map-gl/docs/api-reference/source

if you need any more information please ask

  • What is `data` in this context? – Matt U Dec 06 '21 at 01:49
  • it's a JSON file that contained all the geoJSON I imported then parsed into an object, do it's an object containing the geoJSON – Magnus Jackson Dec 06 '21 at 01:55
  • 1
    Have you verified that the shape is correct when it reaches this code? Clearly the `Source` component disagrees and believes that `data` is missing properties named `type` and `features`. – Matt U Dec 06 '21 at 01:57
  • Yes, data has both a type and features I can console.log both those. – Magnus Jackson Dec 06 '21 at 02:13
  • Can you share those here? – Matt U Dec 06 '21 at 02:15
  • type = ```FeatureCollection```, features return ```0: {type: 'Feature', properties: {…}, geometry: {…}} 1: {type: 'Feature', properties: {…}, geometry: {…}} 2: {type: 'Feature', properties: {…}, geometry: {…}} 3: {type: 'Feature', properties: {…}, geometry: {…}}``` ... up to 23 – Magnus Jackson Dec 06 '21 at 02:24
  • each feature contains ```geometry: {type: 'Point', coordinates: Array(2)} properties: {OBJECTID: 1, HASTUS: 317581, TRANSLINK_ID: 306654, DESCRIPTION: 'Dockside ferry terminal', STREETNAME: 'Ferry St', …} type: "Feature"``` – Magnus Jackson Dec 06 '21 at 02:27
  • Can you show how you are importing the JSON? Are you assigning it a type when you import it? – coagmano Dec 06 '21 at 06:46

1 Answers1

4

Explanation

Let's pull apart this error:

Overload 1 of 2, '(props: SourceProps | Readonly<SourceProps>): Source'
...
Overload 2 of 2, '(props: SourceProps, context: any): Source

At the top level it is showing the two possible ways that you can use the Source component. Assuming you aren't assigning it a context, let's continue looking at Overload 1

Type 'object' is not assignable to type 'string | Feature<Geometry, GeoJsonProperties> | FeatureCollection<Geometry, GeoJsonProperties> | undefined'.

This is telling us that typescript thinks data is an object, but it's expecting it to be specifically a string or a Feature or a FeatureCollection (specifically features of Geometry, GeoJsonProperties)
This tells us that object is not a specific enough type to satisfy the compiler.

Type '{}' is missing the following properties from type 'FeatureCollection<Geometry, GeoJsonProperties>': type, features

Here's it's trying to be helpful by telling us what's missing in the object type. Note that it's reduced your type to an empty object without properties.

Solution

So how do you tell the compiler what data is?
I'm going to assume that you are fetching the data and so typescript is unable to infer it's type automatically

Option 1 - use a type guard to check the incoming data

function isFeatureCollection(data: unknown): data is FeatureCollection<Geometry, GeoJsonProperties> {
    return (
        typeof data === 'object'
        && data !== null
        && 'type' in data
        && 'features' in data
    );
}

Then use the type guard to exit out of the render, and typescript will know that after this check that data will be the type expected by Source

if (!isFeatureCollection(data)) return null;

<Source id="my-data" type="geojson" data={data}>
    <Layer {...layerStyles}/>
</Source>

Option 2 - Cast the type using as to what you expect it to be:

const data = await getData() as FeatureCollection<Geometry, GeoJsonProperties>;

This isn't recommended as you're throwing away Typescript's type guarantee here

coagmano
  • 5,542
  • 1
  • 28
  • 41