如何在打字稿中创建通用接口的通用实现?

问题描述 投票:0回答:1

我想将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>[] };
}

我尝试过提取新界面,但没有成功。

typescript dry react-virtuoso
1个回答
0
投票

您可以创建一个类似工厂的函数来创建 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>();

这行得通吗?

© www.soinside.com 2019 - 2024. All rights reserved.