React D3设置数据时出现Object is of type 'unknown' TS报错
React D3自定义Hook TypeScript类型报错解决方案
问题背景
在React+D3项目中开发负责数据拉取、加工的自定义Hook时,先后遇到两类TypeScript报错:
- 初始实现时useEffect回调内抛出
Object is of type 'unknown'错误 - 调整接口类型定义后,仍存在两处参数类型不匹配错误
错误根因分析
- 初始
unknown报错:D3内置的json()方法默认返回类型为Promise<unknown>,TypeScript无法自动推断拉取到的JSON数据结构,直接对返回值调用数组方法会触发类型校验错误。 - 调整类型后的第一处报错:
timeParse方法的入参要求为string类型,但调整后的联合类型string | Date | null无法保证传入值一定是合法字符串;同时错误地给json()传入了嵌套数组的泛型EventViewerDataTypes[],和本身定义为数组类型的EventViewerDataTypes结构冲突。 - 调整类型后的第二处报错:D3的
json()方法在请求异常、无返回内容时会返回undefined,该类型和useState定义的EventViewerDataTypes | null类型不匹配,无法直接传入setData。 - 额外逻辑问题:原代码直接在
forEach中修改接口返回的原始响应对象,违反React不可变数据原则,容易引发不可预期的渲染问题。
修复步骤
- 拆分类型定义:分别定义接口返回的原始数据类型和加工完成后输出的数据类型,不要用联合类型混同两个阶段的数据结构
- 给
json()传入正确的泛型参数,明确拉取到的原始数据结构,避免数组嵌套 - 增加空值收窄逻辑,处理
json()返回undefined的边界场景,匹配state的类型要求 - 用
map替代forEach生成全新的加工后数据对象,不要直接修改原始响应 - 将
jsonUrl加入useEffect依赖数组,避免url变化时不重新拉取数据的闭包问题
正确实现代码
import { useState, useEffect } from "react" import { json, timeParse } from "d3" const parseTime = timeParse("%d-%m-%Y") // 接口返回的原始数据结构 interface RawEventData { date: string site: string type: string value: string } // 加工完成后最终返回的数据结构 interface ProcessedEventData { date: Date | null site: string type: string value: number } export const useData = (jsonUrl: string) => { const [data, setData] = useState<ProcessedEventData[] | null>(null) useEffect(() => { // 传入原始数据类型泛型,此时json返回类型为Promise<RawEventData[] | undefined> json<RawEventData[]>(jsonUrl).then((rawData) => { // 空值收窄,处理无返回的场景 if (!rawData) { setData(null) return } // 遍历加工生成新的数据对象,不修改原始响应 const processedData = rawData.map((item) => ({ date: parseTime(item.date), // 原始date为string类型,完全符合parseTime入参要求 site: item.site, type: item.type, value: +item.value // 字符串转数字 })) setData(processedData) }) }, [jsonUrl]) return data }
提示:
timeParse方法在日期格式不匹配时会返回null,如果业务场景不允许日期为空,可以在加工逻辑中增加空值校验,过滤无效数据。
内容的提问来源于stack exchange,提问作者b404
相关产品推荐
相关产品推荐

