Next.js组件按下拉选择列排序时遇TypeScript类型错误求助
解决Next.js组件中TypeScript排序类型错误
问题根源
selectedColumn被声明为any类型,TypeScript无法推断它是数据对象的合法键,导致索引类型错误。- 列选择下拉菜单的
value为大写格式(如"Id"),但数据对象的键是小写(如"id"),会导致无法正确获取属性值。 - 未区分字符串类型(
name)和数字类型(id/height)的排序逻辑,直接用减号会引发字符串排序错误。
解决方案
1. 定义明确的数据类型
先为数据项创建类型,让TypeScript明确可用的键:
type DataItem = { id: number; name: string; height: number; };
2. 修正selectedColumn类型与下拉选项
将selectedColumn的类型约束为keyof DataItem | null,同时统一下拉选项的value与数据键的大小写:
const [selectedColumn, setSelectedColumn] = useState<keyof DataItem | null>(null); // 列选择Dropdown的options修正为: options={[ { label: "id", value: "id" }, { label: "name", value: "name" }, { label: "height", value: "height" }, ]}
3. 编写类型安全的排序逻辑
根据选中列的类型,分别处理数字和字符串的排序逻辑:
const orderChangeHandler = (e: { value: Order }) => { if (!selectedColumn) return; setSelectedOrder(e.value); const sortedData = [...data]; sortedData.sort((a, b) => { const valA = a[selectedColumn]; const valB = b[selectedColumn]; // 数字类型排序 if (typeof valA === "number" && typeof valB === "number") { return e.value === "ascending" ? valA - valB : valB - valA; } // 字符串类型排序 if (typeof valA === "string" && typeof valB === "string") { return e.value === "ascending" ? valA.localeCompare(valB) : valB.localeCompare(valA); } return 0; }); setData(sortedData); };
完整修正后的组件代码
import React, { useState } from "react"; import classes from "./SortingBar.module.css"; import { Dropdown } from "primereact/dropdown"; type Props = {}; type Order = "ascending" | "descending"; type DataItem = { id: number; name: string; height: number; }; const SortingBar = (props: Props) => { const [selectedOrder, setSelectedOrder] = useState<Order | null>(null); const [selectedColumn, setSelectedColumn] = useState<keyof DataItem | null>(null); const [data, setData] = useState<DataItem[]>([ { id: 1, name: "A", height: 1.67 }, { id: 3, name: "C", height: 1.65 }, { id: 2, name: "B", height: 1.68 }, { id: 4, name: "D", height: 1.7 }, { id: 6, name: "F", height: 1.69 }, { id: 5, name: "E", height: 1.66 }, ]); const orderChangeHandler = (e: { value: Order }) => { if (!selectedColumn) return; setSelectedOrder(e.value); const sortedData = [...data]; sortedData.sort((a, b) => { const valA = a[selectedColumn]; const valB = b[selectedColumn]; if (typeof valA === "number" && typeof valB === "number") { return e.value === "ascending" ? valA - valB : valB - valA; } if (typeof valA === "string" && typeof valB === "string") { return e.value === "ascending" ? valA.localeCompare(valB) : valB.localeCompare(valA); } return 0; }); setData(sortedData); }; return ( <div> <div className={classes.sidebarContent}> <div className={classes.description}> <h5 className=" text-gray-800 mt-3 mb-3">Sorting</h5> </div> <div> <div className="col-12"> <h6>Select field </h6> <Dropdown className="w-full" placeholder="Select column" options={[ { label: "id", value: "id" }, { label: "name", value: "name" }, { label: "height", value: "height" }, ]} onChange={(e) => setSelectedColumn(e.value)} value={selectedColumn} /> </div> <div className="col-12"> <h6>Select order </h6> <Dropdown className="w-full" placeholder="Select order" options={[ { label: "Ascending", value: "ascending" }, { label: "Descending", value: "descending" }, ]} onChange={orderChangeHandler} value={selectedOrder} /> </div> <div className="col-12"> {data.map((item) => ( <div key={item.id} className="flex flex-wrap align-items-center"> <div className="col-4">{item.id}</div> <div className="col-4">{item.name}</div> <div className="col-4">{item.height}</div> </div> ))} </div> </div> </div> </div> ); }; export default SortingBar;
关键说明
- 使用
keyof DataItem约束selectedColumn,确保它只能是数据对象的合法键,彻底消除TypeScript索引错误。 - 统一下拉选项的
value与数据键的大小写,避免属性获取失败。 - 区分数字和字符串的排序逻辑,保证不同类型数据都能正确排序,同时避免类型错误。
内容的提问来源于stack exchange,提问作者Mustafa KANLI
相关产品推荐
相关产品推荐

