简体   繁体   English

Typescript 和 React:如何从父组件动态推断类型?

[英]Typescript and React: How to dynamically infer types from the parent component?

I have a generic component that I use to build specific tables along the code.我有一个通用组件,用于沿代码构建特定表。 Let's call it GenericTable .我们称之为GenericTable Its workflow looks like this:它的工作流程如下所示:

Table Rendering Workflow表格渲染工作流程

In order to simplify the question, let's say the GenericTable has only two props: columns and rows .为了简化问题,假设GenericTable只有两个道具: columnsrows

export const Page1 = () => {
return (
    <GenericTable
      columns={page1Columns}
      rows={page1Rows}
    />
  );
};

export const Page2 = () => {
    return (
        <GenericTable
          columns={page2Columns}
          rows={page2Rows}
        />
      );
    };

Let's say that the types of the columns and rows may vary from page to page.假设columnsrows的类型可能因页面而异。 For instance, Page1 may have a table only showing numbers while Page2 may have a more sophisticated table with strings, numbers and even other components.例如, Page1可能有一个只显示数字的表格,而Page2可能有一个更复杂的表格,其中包含字符串、数字甚至其他组件。 This way, the properties and types of the GenericTable should look something like this:这样, GenericTablepropertiestypes应该如下所示:

type GenericTableProps<ColumnType, RowType> {
    columns: ColumnType;
    rows: RowType;
  }
    
  export const GenericTable = <
    ColumnType extends Page1ColumnType | Page2ColumnType,
    RowType extends Page1RowType | Page2RowType
  >(
    props: GenericProps<ColumnType, RowType>
  ) => {
    // build the table here using the columns and rows props
  }

The problem here is, since I may have more than just twos pages calling the GenericTable , I do not want to hard code the types such as Page1ColumnType , Page1RowType and so on.这里的问题是,由于我可能有不止两个页面调用GenericTable ,我不想硬编码Page1ColumnTypePage1RowType等类型。 How can I dynamically infer the columns and rows type from the page that is passing it?如何从传递它的页面动态推断列和行类型?

For example, in case a Page3 calls in the GenericTable , how can it infer that the ColumnType will extend the Page3ColumnType without hardcoding it.例如,如果Page3GenericTable中调用,它如何推断ColumnType扩展Page3ColumnType而无需对其进行硬编码。

COnsider this example:考虑这个例子:

type Page1ColumnType = {
    tag: 'Page1ColumnType'
}
type Page2ColumnType = {
    tag: 'Page2ColumnType'
}

type Page1RowType = {
    tag: 'Page1RowType'
}

type Page2RowType = {
    tag: 'Page2RowType'
}

type GenericTableProps<ColumnType, RowType> = {
    columns: ColumnType;
    rows: RowType;
}

export const GenericTable = <
    ColumnType extends Page1ColumnType | Page2ColumnType,
    RowType extends Page1RowType | Page2RowType
>(
    props: GenericTableProps<ColumnType, RowType>
) => { }

Type signature of GenericTable is unsafe, because ColumnType and RowType are not related/binded to each other. GenericTable的类型签名是不安全的,因为ColumnTypeRowType彼此不相关/不绑定。 It means that this call is perfectly valid from typescript point of view:这意味着从 typescript 的角度来看,这个调用是完全有效的:

const result = GenericTable({
    columns: {
        tag: 'Page1ColumnType'
    },
    rows: {
        tag: 'Page2RowType'
    }
})

Have you noticed that columns are Page1 and rows are Page2 .您是否注意到列是Page1和行是Page2 In order to bind columns and rows, you need to make it as a part of one data structure:为了绑定列和行,您需要将其作为一个数据结构的一部分:


type GenericTableProps<ColumnType, RowType> = {
    columns: ColumnType;
    rows: RowType;
}

type DataStructure =
    | GenericTableProps<Page1ColumnType, Page1RowType>
    | GenericTableProps<Page2ColumnType, Page2RowType>

export const GenericTable = (
    props: DataStructure
) => { }

// ERROR
GenericTable({
    columns: {
        tag: 'Page1ColumnType'
    },
    rows: {
        tag: 'Page2RowType' // wrong value
    }
})

// OK
GenericTable({
    columns: {
        tag: 'Page1ColumnType'
    },
    rows: {
        tag: 'Page1RowType' // ok
    }
})

PLayground操场

If you don't want to hardcode all allowed states up front, you still need to some how map types.如果您不想预先对所有允许的状态进行硬编码,您仍然需要了解 map 的类型。 If you will provide me with expected interface of row and column I try to write generic function, because I don't know the shape of row and column and how they are related between each other如果你会给我提供预期的行和列接口,我会尝试编写通用 function,因为我不知道行和列的形状以及它们之间的关系

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM