我想将DRY应用于以下情况。有一个通用接口“SomeInterface”,我需要该接口的几个实现,除了显式类型定义之外,它们恰好都是相等的。我想要一个通用的类/接口/表达式来收集所有的共性。
为了更清楚起见,我使用
react-virtuoso
并且我想要几个 TableComponents
,如下所示。我不想声明 VirtuosoTableComponents_booklists
和 VirtuosoTableComponents_books
,而是想要类似 VirtuosoTableComponents<T>
的东西,然后像 components={VirtuosoTableComponents<booklists>}
一样使用它。
表.tsx
import { Book, BookList } from './data-context';
const VirtuosoTableComponents_booklists: TableComponents<BookList> = {
// eslint-disable-next-line react/display-name
Scroller: React.forwardRef<HTMLDivElement>((props, ref) => <TableContainer component={Paper} {...props} ref={ref} />),
Table: props => <Table {...props} sx={{ borderCollapse: 'separate', tableLayout: 'fixed' }} />,
TableHead,
TableRow: props => <TableRow {...props} />,
// eslint-disable-next-line react/display-name
TableBody: React.forwardRef<HTMLTableSectionElement>((props, ref) => <TableBody {...props} ref={ref} />)
};
const VirtuosoTableComponents_books: TableComponents<Book> = {
// eslint-disable-next-line react/display-name
Scroller: React.forwardRef<HTMLDivElement>((props, ref) => <TableContainer component={Paper} {...props} ref={ref} />),
Table: props => <Table {...props} sx={{ borderCollapse: 'separate', tableLayout: 'fixed' }} />,
TableHead,
TableRow: props => <TableRow {...props} />,
// eslint-disable-next-line react/display-name
TableBody: React.forwardRef<HTMLTableSectionElement>((props, ref) => <TableBody {...props} ref={ref} />)
};
export const MyTables = () : React.JSX.Element => {
const [data, updateData] = React.useState(undefined as unknown as CtxData);
React.useEffect(() => {
// .... fetch data ....
updateData(response);
}
// function fixedHeaderContent_booklists ..
// function fixedHeaderContent_books ..
// function rowContent_booklists ..
// function rowContent_books ..
return (
<>
<DataContext.Provider value={data}>
<div><p>Book Lists</p></div>
<TableVirtuoso
data={data.booklists.rows}
components={VirtuosoTableComponents_booklists}
fixedHeaderContent={fixedHeaderContent_booklists}
itemContent={rowContent_booklists}
/>
<div><p>Books</p></div>
<TableVirtuoso
data={data.books.rows}
components={VirtuosoTableComponents_books}
fixedHeaderContent={fixedHeaderContent_books}
itemContent={rowContent_books}
/>
</DataContext.Provider>
</>
)
}
数据上下文.ts
export interface BookList {
bookRef: string[]
}
export interface Book {
title: string;
author: string;
}
export interface ColumnData<T> {
dataKey: keyof T;
label: string;
width: number;
}
export interface CtxData {
booklists: { rows: BookList[]; columns: ColumnData<BookList>[] };
books: { rows: Book[]; columns: ColumnData<Book>[] };
}
我尝试过提取新界面,但没有成功。
您可以创建一个类似工厂的函数来创建 TableComponents 对象:
function createTableComponents<T>(): TableComponents<T> {
return {
// eslint-disable-next-line react/display-name
Scroller: React.forwardRef<HTMLDivElement>((props, ref) => <TableContainer component={Paper} {...props} ref={ref} />),
Table: props => <Table {...props} sx={{ borderCollapse: 'separate', tableLayout: 'fixed' }} />,
TableHead,
TableRow: props => <TableRow {...props} />,
// eslint-disable-next-line react/display-name
TableBody: React.forwardRef<HTMLTableSectionElement>((props, ref) => <TableBody {...props} ref={ref} />)
};
};
这可以让你做:
const VirtuosoTableComponents_booklists = createTableComponents<BookList>();
const VirtuosoTableComponents_books = createTableComponents<Book>();
这行得通吗?