TypeScript索引签名错误:SetStateAction与索引类型问题求助
TypeScript索引签名与状态类型错误修复
问题描述
我是TypeScript和索引签名的新手,碰到两个代码错误无法解决:
- 在
setData(sorted)处提示:类型{ id: string; jobName: string; created: string; modified: string; }[]无法赋值给SetStateAction<never[]> - 在
(b[sortProperty])处提示:表达式类型string无法用于索引,存在隐式any类型
原始代码
data.js
export const tasks = [ { id: "1", jobName: 'MK-00544 • Spacecraft', created: '2016-09-03', modified: '2016-09-04' }, { id: "2", jobName: 'MK-00545 • Spacecraft', created: '2017-09-26', modified: '2018-09-29' }, { id: "3", jobName: 'MK-00546 • Spacecraft', created: '2019-10-03', modified: '2022-12-08' }, { id: "4", jobName: 'MK-00547 • Spacecraft', created: '2020-09-12', modified: '2021-09-03' }, { id: "5", jobName: 'MK-005478 • Spacecraft', created: '2019-09-03', modified: '2019-09-03' }, { id: "6", jobName: 'MK-00549 • Spacecraft', created: '2019-09-03', modified: '2019-09-03' } ]
Job.tsx
interface Task { [key: string]: string } const [data, setData] = useState<Task>([]) const [sortType, setSortType] = useState('jobName') useEffect(() => { const sortArray = (type: string) => { interface StringIndexedObject { [key: string]: string } const types: StringIndexedObject = { jobName: 'jobName', created: 'created', modified: 'modified' } interface AnotherStringIndexedObject { [key: string]: keyof Task } const sortProperty = types[type] const sorted: AnotherStringIndexedObject = [...tasks].sort( (a, b) => new Date(b[sortProperty]) - new Date(a[sortProperty]) ) console.log(sorted) setData(sorted) } sortArray(sortType) }, [sortType]) return ( <div className="font-bold">Sort by:</div> <select onChange={(e) => setSortType(e.target.value)} className="text-center px-5 bg-gray-200 rounded-xl" > <option value="id">Id</option> <option value="jobName">Job name</option> <option value="created">Newest</option> <option value="modified">Last modified</option> </select> <div>({tasks.length} users)</div> {data.map((task) => ( <tr key={task.id} className="tableau text-center cursor-pointer" onClick={() => router.push(`/job/${task.id}`)} > <td className="py-3">{task.jobName}</td> <td className="py-3"> <div className="flex items-center gap-5 justify-center"> {task.created} </div> </td> <td className="py-3"> <div className="flex items-center gap-5 justify-center"> {task.modified} </div> </td> ))}
错误修复方案
1. 修复状态类型不匹配问题
- 原
Task接口使用宽泛的索引签名,改为明确定义每个字段类型,避免隐式any:interface Task { id: string; jobName: string; created: string; modified: string; } - 状态
data是Task数组,所以useState的泛型应该是Task[],而非单个Task:const [data, setData] = useState<Task[]>([])
2. 修复索引类型不兼容问题
- 把
types的类型定义为Record<string, keyof Task>,确保sortProperty的类型是Task的键,而非普通string:const types: Record<string, keyof Task> = { jobName: 'jobName', created: 'created', modified: 'modified', id: 'id' // 补充select中用到的id选项 } - 移除多余的
AnotherStringIndexedObject接口,sorted的类型应为Task[]:const sorted: Task[] = [...tasks].sort( (a, b) => new Date(b[sortProperty]) - new Date(a[sortProperty]) ) - 同时,
sortArray的参数type可以限定为keyof Task,进一步增强类型安全:const sortArray = (type: keyof Task) => { ... }
修正后的完整Job.tsx代码
import { useState, useEffect } from 'react'; import { tasks } from './data'; import { useRouter } from 'next/router'; interface Task { id: string; jobName: string; created: string; modified: string; } const Job = () => { const [data, setData] = useState<Task[]>([]); const [sortType, setSortType] = useState<keyof Task>('jobName'); const router = useRouter(); useEffect(() => { const sortArray = (type: keyof Task) => { const types: Record<string, keyof Task> = { jobName: 'jobName', created: 'created', modified: 'modified', id: 'id' }; const sortProperty = types[type]; const sorted: Task[] = [...tasks].sort((a, b) => { // 处理id的字符串转数字排序 if (sortProperty === 'id') { return Number(b.id) - Number(a.id); } // 日期字段排序 return new Date(b[sortProperty]) - new Date(a[sortProperty]); }); setData(sorted); }; sortArray(sortType); }, [sortType]); return ( <div> <div className="font-bold">Sort by:</div> <select onChange={(e) => setSortType(e.target.value as keyof Task)} className="text-center px-5 bg-gray-200 rounded-xl" value={sortType} > <option value="id">Id</option> <option value="jobName">Job name</option> <option value="created">Newest</option> <option value="modified">Last modified</option> </select> <div>({tasks.length} users)</div> <table> <tbody> {data.map((task) => ( <tr key={task.id} className="tableau text-center cursor-pointer" onClick={() => router.push(`/job/${task.id}`)} > <td className="py-3">{task.jobName}</td> <td className="py-3"> <div className="flex items-center gap-5 justify-center"> {task.created} </div> </td> <td className="py-3"> <div className="flex items-center gap-5 justify-center"> {task.modified} </div> </td> </tr> ))} </tbody> </table> </div> ); }; export default Job;
内容的提问来源于stack exchange,提问作者Rom-888
相关产品推荐
相关产品推荐

