You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 06:50:30