我正在开发 ReactJS Typescript 应用程序并使用 MUI 作为组件库。我需要创建一个功能齐全的 CRUD 数据网格(如 MUI 数据网格组件)。在示例中,大多数列都具有一些相同的属性。我想用所需的通用道具创建一个单独的对象并应用于所有列,但我不断收到附加的打字稿警告/错误。我做错了什么?
警告/错误:
代码:
import * as React from "react";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import AddIcon from "@mui/icons-material/Add";
import EditIcon from "@mui/icons-material/Edit";
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
import SaveIcon from "@mui/icons-material/Save";
import CancelIcon from "@mui/icons-material/Close";
import {
GridRowsProp,
GridRowModesModel,
GridRowModes,
DataGrid,
GridColDef,
GridToolbarContainer,
GridActionsCellItem,
GridEventListener,
GridRowId,
GridRowModel,
GridRowEditStopReasons,
GridSlots,
} from "@mui/x-data-grid";
import {
randomCreatedDate,
randomTraderName,
randomId,
randomArrayItem,
} from "@mui/x-data-grid-generator";
const roles = ["Market", "Finance", "Development"];
const randomRole = () => {
return randomArrayItem(roles);
};
const initialRows: GridRowsProp = [
{
id: randomId(),
name: randomTraderName(),
age: 25,
joinDate: randomCreatedDate(),
role: randomRole(),
},
{
id: randomId(),
name: randomTraderName(),
age: 36,
joinDate: randomCreatedDate(),
role: randomRole(),
},
{
id: randomId(),
name: randomTraderName(),
age: 19,
joinDate: randomCreatedDate(),
role: randomRole(),
},
{
id: randomId(),
name: randomTraderName(),
age: 28,
joinDate: randomCreatedDate(),
role: randomRole(),
},
{
id: randomId(),
name: randomTraderName(),
age: 23,
joinDate: randomCreatedDate(),
role: randomRole(),
},
];
interface EditToolbarProps {
setRows: (newRows: (oldRows: GridRowsProp) => GridRowsProp) => void;
setRowModesModel: (
newModel: (oldModel: GridRowModesModel) => GridRowModesModel
) => void;
}
function EditToolbar(props: EditToolbarProps) {
const { setRows, setRowModesModel } = props;
const handleClick = () => {
const id = randomId();
setRows((oldRows) => [...oldRows, { id, name: "", age: "", isNew: true }]);
setRowModesModel((oldModel) => ({
...oldModel,
[id]: { mode: GridRowModes.Edit, fieldToFocus: "name" },
}));
};
return (
<GridToolbarContainer>
<Button startIcon={<AddIcon />} onClick={handleClick}>
Add record
</Button>
</GridToolbarContainer>
);
}
export default function FullFeaturedCrudGrid() {
const [rows, setRows] = React.useState(initialRows);
const [rowModesModel, setRowModesModel] = React.useState<GridRowModesModel>(
{}
);
const handleRowEditStop: GridEventListener<"rowEditStop"> = (
params,
event
) => {
if (params.reason === GridRowEditStopReasons.rowFocusOut) {
event.defaultMuiPrevented = true;
}
};
const handleEditClick = (id: GridRowId) => () => {
setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.Edit } });
};
const handleSaveClick = (id: GridRowId) => () => {
setRowModesModel({ ...rowModesModel, [id]: { mode: GridRowModes.View } });
};
const handleDeleteClick = (id: GridRowId) => () => {
setRows(rows.filter((row) => row.id !== id));
};
const handleCancelClick = (id: GridRowId) => () => {
setRowModesModel({
...rowModesModel,
[id]: { mode: GridRowModes.View, ignoreModifications: true },
});
const editedRow = rows.find((row) => row.id === id);
if (editedRow!.isNew) {
setRows(rows.filter((row) => row.id !== id));
}
};
const processRowUpdate = (newRow: GridRowModel) => {
const updatedRow = { ...newRow, isNew: false };
setRows(rows.map((row) => (row.id === newRow.id ? updatedRow : row)));
return updatedRow;
};
const handleRowModesModelChange = (newRowModesModel: GridRowModesModel) => {
setRowModesModel(newRowModesModel);
};
const commonColumnProps: Partial<GridColDef> = {
headerAlign: "center",
align: "center",
sortable: false,
flex: 1,
editable: true,
};
const columnDefinitions: GridColDef[] = [
{ field: "name", headerName: "Name", width: 180 },
{
field: "age",
headerName: "Age",
type: "number",
width: 80,
},
{
field: "joinDate",
headerName: "Join date",
type: "date",
},
{
field: "role",
headerName: "Department",
width: 220,
type: "singleSelect",
valueOptions: ["Market", "Finance", "Development"],
},
];
const columns = columnDefinitions.map((columnDef) => {
const actionsObject = {
field: "actions",
type: "actions",
headerName: "Actions",
width: 100,
cellClassName: "actions",
getActions: ({ id }) => {
const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
if (isInEditMode) {
return [
<GridActionsCellItem
icon={<SaveIcon />}
label="Save"
sx={{
color: "primary.main",
}}
onClick={handleSaveClick(id)}
/>,
<GridActionsCellItem
icon={<CancelIcon />}
label="Cancel"
className="textPrimary"
onClick={handleCancelClick(id)}
color="inherit"
/>,
];
}
return [
<GridActionsCellItem
icon={<EditIcon />}
label="Edit"
className="textPrimary"
onClick={handleEditClick(id)}
color="inherit"
/>,
<GridActionsCellItem
icon={<DeleteIcon />}
label="Delete"
onClick={handleDeleteClick(id)}
color="inherit"
/>,
];
},
};
return {
...commonColumnProps,
...columnDef,
...actionsObject,
};
});
return (
<Box
sx={{
height: 500,
width: "100%",
"& .actions": {
color: "text.secondary",
},
"& .textPrimary": {
color: "text.primary",
},
}}
>
<DataGrid
rows={rows}
columns={columns}
editMode="row"
rowModesModel={rowModesModel}
onRowModesModelChange={handleRowModesModelChange}
onRowEditStop={handleRowEditStop}
processRowUpdate={processRowUpdate}
slots={{
toolbar: EditToolbar as GridSlots["toolbar"],
}}
slotProps={{
toolbar: { setRows, setRowModesModel },
}}
/>
</Box>
);
}
堆栈闪电战:
如果您对数据的结构有信心,快速解决方法是断言列的类型。这告诉打字稿这些对象符合
GridColDef
:
const columns: GridColDef[] = columnDefinitions.map((columnDef) => {
const actionsObject = {
field: 'actions',
type: 'actions',
headerName: 'Actions',
width: 100,
cellClassName: 'actions',
getActions: ({ id }) => {
const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
if (isInEditMode) {
return [
<GridActionsCellItem
icon={<SaveIcon />}
label="Save"
sx={{
color: 'primary.main',
}}
onClick={handleSaveClick(id)}
/>,
<GridActionsCellItem
icon={<CancelIcon />}
label="Cancel"
className="textPrimary"
onClick={handleCancelClick(id)}
color="inherit"
/>,
];
}
return [
<GridActionsCellItem
icon={<EditIcon />}
label="Edit"
className="textPrimary"
onClick={handleEditClick(id)}
color="inherit"
/>,
<GridActionsCellItem
icon={<DeleteIcon />}
label="Delete"
onClick={handleDeleteClick(id)}
color="inherit"
/>,
];
},
};
return {
...commonColumnProps,
...columnDef,
...actionsObject,
};
}) as GridColDef[];