Home > Mobile >  Object is of type 'unknown' error while setting data in react d3
Object is of type 'unknown' error while setting data in react d3

Time:07-06

I am trying to set up a custom hook that fetches data, does some manipulations on the data and returns the manipulated data in a react d3 application. The data type is

interface EventViewerDataTypes {
    date: string
    site: string
    type: string
    value: string
}[]

Inside the useEffect hook there is an error Object is of type 'unknown'.

import { useState, useEffect } from "react"
import { json, timeParse } from "d3"

const parseTime = timeParse("%d-%m-%Y")

interface EventViewerDataTypes {
  date: string
  site: string
  type: string
  value: string
}[]
export const useData = (jsonUrl: string) => {
  const [data, setData] = useState<EventViewerDataTypes | null>(null)
  useEffect(() => {
       json(jsonUrl).then((data) => {
           data.forEach((d) => {
                d.date = parseTime(d.date)
                d.value =  d.value
            })
            setData(data)
        })
    }, [])
    return data
}

I'm a bit struggling with typescript and any help, or recommendations would be valuable.

Update

With the help of Robby Cornelissen, I made some progress and updated the code, and still some issues. So I tried updating the EventViewerDataTypes as

interface EventViewerDataTypes {
    date: string | Date | null
    site: string
    type: string
    value: string | number
}[]

But still have some errors

json<EventViewerDataTypes[]>(jsonUrl).then((data) => {
    data?.forEach((d) => {

        // Error!
        d.date = parseTime(d.date) 
        // Argument of type 'string | Date | null' is not assignable to parameter of type 'string'. Type 'null' is not assignable to type 'string'

        d.value =  d.value
    })

    // Error!
    //Argument of type 'EventViewerDataTypes[] | undefined' is not assignable to parameter of type 'SetStateAction<EventViewerDataTypes | null>'
     setData(data) 

})

CodePudding user response:

There are a number of issues with your code:

Untyped JSON response

There is no way for the TypeScript compiler to infer what type will be retrieved from the jsonUrl.

According to the type definition, the json() function has a generic constraint that lets you specify the expected return type, so this should fix it:

json<EventViewerDataTypes>(jsonUrl).then((data) => {
  /* ... */
});

Handling of an undefined JSON response

Since from the type definition it seems that the json() function can also return undefined, you might also need to use the optional chaining operator (or an if-check) before looping over data:

data?.forEach((d) => {
  /* ... */
});

In case the setData(data) function you call after doesn't accept undefined, you're probably better off with an explicit if-check and either calling setData(null) or not calling setData() at all.

Discrepancies between JSON types and model types

There are discrepancies between the JSON data you retrieve, and the way you wish to model them in your application. First of all, it's more readable and convenient to type a single EventViewerDataType object (instead of EventViewerDataTypes), and then use EventViewerDataType[] whenever you need an array.

Based on your processing logic, this is how I think EventViewerDataType should be typed:

interface EventViewerDataType {
  date: Date | null;
  site: string;
  type: string;
  value: number;
}

Then, since your JSON seems to contain only strings, I would use a mapped type to define the data transfer object as:

type StringValues<T> = {
  [K in keyof T]: string;
}

Then, in your processing logic, instead of using forEach(), use map() to map from your JSON format objects (StringValues<EventViewerDataType>[]) to your model objects (EventViewerDataType[]).

  • Related