reactjs typescript 索引签名错误:类型错误:类型的参数不能赋给类型为“SetStateAction〈never[]>”的参数

uyto3xhc  于 2023-01-12  发布在  React
关注(0)|答案(1)|浏览(537)

我是 typescript 和索引签名的新手,我不知道如何在我的代码中解决这个错误。我假设我需要在变量sortProperty上对变量sorted进行一些操作,但是我找不到答案。我有2个错误。一个在 setData(sorted)
类型{ id:编号;作业名称:字符串;创建日期:字符串;已修改:字符串; }[]"不能赋给类型为“SetStateAction〈never[]〉”的参数
另一个位于 (B[sortProperty])
元素隐式具有“any”类型,因为“string”类型的表达式不能用于索引
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'
    }
  ]

作业.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>
              ))}
pftdvrlh

pftdvrlh1#

这里有一堆问题,它们都是相关的,当一个变量的类型不完整或不正确时,它可能会在使用该变量的其他地方引起问题。
组件的工作是排序和呈现一个任务对象数组,它内部存储了两种状态:
1.当前排序属性。
1.已排序任务的数组。
(Note:排序数组1不 * 需要 * 是一个状态,因为它是一个派生值。个人而言,我会使用useMemo而不是useStateuseEffect,但您所拥有的将起作用,所以让我们保留它并专注于TypeScript问题)
以下是我修复的问题:

1.描述任务对象的类型。

不是每个字符串都是有效的键,我们有一些已知的属性,仅此而已。

interface Task {
    id: string;
    jobName: string;
    created: string;
    modified: string;
}

2.设置data状态的类型。

它是一个任务数组,也就是Task[]。这里需要一个类型,因为初始值是一个类型为never[]的空数组。如果初始数组不为空,则可以自动推断。

const [data, setData] = useState<Task[]>([])

3.将types对象定义为从stringkeyof Task的Map。

现在sortProperty具有keyof Task类型,这意味着它始终是Task的属性。

const sortArray = (type: string) => {
    interface StringIndexedObject {
        [key: string]: keyof Task
    }
    const types: StringIndexedObject = {
        jobName: 'jobName',
        created: 'created',
        modified: 'modified'
    }
    const sortProperty = types[type];

您还可以执行以下操作:

const types: Record<string, keyof Task> = {

4.删除了AnotherStringIndexedObject类型。

排序后的数组不是一个对象,它是一个数组Task[],你可以写const sorted: Task[],但你不需要写。

5.删除了new Date处理。

如果排序类型是'jobName''id',这就没有意义了。什么是new Date('MK-005478 • Spacecraft')?对于 * 是 * 日期的字段,我们可以将ISO字符串作为字符串进行比较。

6.使用lodash sortBy进行排序。

你可以定义一个自定义的比较函数,但是我发现这真的很烦人。

const sorted = sortBy(tasks, sortProperty);

7.将数据文件从data.js重命名为data.ts

如果是TypeScript文件,则导入的tasks变量将根据其值具有正确的类型。
Job.tsx

import React, { useState, useEffect } from 'react';
import { sortBy } from 'lodash';
import { useRouter } from 'next/router';
import { tasks } from './data';

export interface Task {
    id: string;
    jobName: string;
    created: string;
    modified: string;
}

export const Job = () => {
    const router = useRouter();

    const [data, setData] = useState<Task[]>([])
    const [sortType, setSortType] = useState('jobName')

    useEffect(() => {
        const sortArray = (type: string) => {
            interface StringIndexedObject {
                [key: string]: keyof Task
            }
            const types: StringIndexedObject = {
                jobName: 'jobName',
                created: 'created',
                modified: 'modified'
            }
            const sortProperty = types[type];
            const sorted = sortBy(tasks, sortProperty);
            console.log(sorted)
            setData(sorted)
        }

        sortArray(sortType)
    }, [sortType]);

    return (
        <div>
            <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>
                </tr>
            ))}
        </div>
    )
}

相关问题