如何正确定义 antd 可编辑表格列的类型

huangapple go评论70阅读模式
英文:

How to properly define antd editable table columns type

问题

Here's the translation of your code portion:

我正在使用Antd和TypeScript构建一个可编辑的表格,遵循指南 [antd: table edit row](https://ant.design/components/table#components-table-demo-edit-row)。

目前,它作为一个可编辑表格工作良好,无论是编辑还是显示数据。

然而,由于我在使用TypeScript,某些列的类型出现了错误。

这是我的Item定义和列的值

```typescript
interface CleanFilterItemLabel {
    key: string;
    name: string;
    color?: string;
}

interface CleanFilterItem {
    id: React.Key,
    state: string,
    keyword: string,
    create_at: number,
    edit_at: number,

    author?: string,
    level?: number,
    group?: number,
    labels?: CleanFilterItemLabel[];
}

const edit_tabel_column = [
    {
        title: t("editPage.level"),
        dataIndex: 'level',
        editable: true,
    },
    // 其他列...
]

const mergedEditColumns = edit_tabel_column.map((col) => {
    if (!col.editable) {
        return col;
    }
    return {
        ...col,
        onCell: (record: CleanFilterItem) => ({
            record,
            inputType: col.dataIndex,
            dataIndex: col.dataIndex,
            title: col.title,
            editing: isEditing(record),
        }),
    };
})

<Form form={form} component={false}>
    <Table 
        components={{
            body: {
                cell: EditableCell
            }
        }}
        rowSelection={rowSelection} 
        columns={mergedEditColumns} // 这里出现类型错误
        className={style.customTable}
        dataSource={tableData} 
        pagination={{ pageSize: 5 }}
        scroll={{ y: 360 }}
        rowKey={"id"}
    />
</Form>

这导致了以下错误:

类型 '{ title: string; dataIndex: string; editable: boolean; filters?: undefined; filterSearch?: undefined; onFilter?: undefined; render?: undefined; ellipsis?: undefined; sorter?: undefined; } | { title: string; ... 7 more ...; sorter?: undefined; } | ... 6 more ... | { ...; }[]' 不能分配给类型 'ColumnType<CleanFilterItem> | ColumnGroupType<CleanFilterItem>[]'  类型 '{ title: string; dataIndex: string; editable: boolean; filters?: undefined; filterSearch?: undefined; onFilter?: undefined; render?: undefined; ellipsis?: undefined; sorter?: undefined; } | { title: string; ... 7 more ...; sorter?: undefined; } | ... 6 more ... | { ...; }' 不能分配给类型 'ColumnType<CleanFilterItem> | ColumnGroupType<CleanFilterItem>'    类型 '{ title: string; dataIndex: string; editable: boolean; filters: { text: string; value: string; }[]; filterSearch: boolean; onFilter: (value: string, record: any) => boolean; render: (state: string) => JSX.Element; ellipsis?: undefined; sorter?: undefined; }' 不能分配给类型 'ColumnType<CleanFilterItem> | ColumnGroupType<CleanFilterItem>'      类型 '{ title: string; dataIndex: string; editable: boolean; filters: { text: string; value: string; }[]; filterSearch: boolean; onFilter: (value: string, record: any) => boolean; render: (state: string) => JSX.Element; ellipsis?: undefined; sorter?: undefined; }' 不能分配给类型 'ColumnType<CleanFilterItem>'        属性 'onFilter' 的类型不兼容。
          类型 '(value: string, record: any) => boolean' 不能分配给类型 '(value: string | number | boolean, record: CleanFilterItem) => boolean'            参数 'value''value' 的类型不兼容。
              类型 'string | number | boolean' 不能分配给类型 'string'。ts(2322)
InternalTable.d.ts(14, 5): 预期类型位于此处 'columns' 属性声明在类型 'IntrinsicAttributes & TableProps<CleanFilterItem> & { children?: ReactNode; } & { ref?: Ref<HTMLDivElement> | undefined; }'

我已经检查了这个问题 columns type error when using a custom sorter function on Ant Design table,并尝试将以下定义添加到我的列,但仍然失败:

const edit_tabel_column: (ColumnsType<CleanFilterItem> & {editable?: boolean}[]) = []

我不擅长这种复杂的类型定义,那么我应该如何给它一个正确的定义?


<details>
<summary>英文:</summary>

I&#39;m working on build an editable table using antd in typescript, following the guide [antd: table edit row](https://ant.design/components/table#components-table-demo-edit-row).

For now it works fine as an editable table, whether editing or displaying data.

However, since i&#39;m using typescript, there&#39;re some errors with column type.

Here&#39;s my Item definition and column value.

```typescript
interface CleanFilterItemLabel {
    key: string;
    name: string;
    color?: string;
}

interface CleanFilterItem {
    id: React.Key,
    state: string,
    keyword: string,
    create_at: number,
    edit_at: number,

    author?: string,
    level?: number,
    group?: number,
    labels?: CleanFilterItemLabel[];
}

  const edit_tabel_column = [
    {
        title: t(&quot;editPage.level&quot;),
        dataIndex: &#39;level&#39;,
        editable: true,
    },
    // {
    //     title: t(&quot;editPage.labels&quot;),
    //     dataIndex: &#39;labels&#39;,
    //     editable: true,
    //     render: (labels: any) =&gt; (
    //       &lt;&gt;
    //         {labels.map((label: any) =&gt; {
    //           return (
    //             &lt;Tag key={label.key}&gt;
    //               {label.name}
    //             &lt;/Tag&gt;
    //           )
    //         })}
    //       &lt;/&gt;
    //     ),
    // },
    {
        title: t(&quot;editPage.group&quot;),
        dataIndex: &#39;group&#39;,
        editable: true,
    },
    {
      title: t(&quot;editPage.state&quot;),
      dataIndex: &#39;state&#39;,
      editable: true,
      filters: [
        {
          text: t(&quot;editPage.enabled&quot;),
          value: &#39;open&#39;,
        },
        {
          text: t(&quot;editPage.disabled&quot;),
          value: &#39;closed&#39;
        }
      ],
      filterSearch: false,
      onFilter: (value: string, record: any) =&gt; record.state === value,
      render: (state: string) =&gt; (
        &lt;&gt;
          {state === &#39;open&#39; ? &lt;Badge status=&quot;error&quot; text={t(&quot;editPage.disabled&quot;)}/&gt; : &lt;Badge status=&quot;success&quot; text={t(&quot;editPage.enabled&quot;)}/&gt;}
        &lt;/&gt;
        ),
    },
    {
        title: t(&quot;editPage.keyword&quot;),
        dataIndex: &#39;keyword&#39;,
        editable: true,
        ellipsis: {
            showTitle: false,
        },
        ...getColumnSearchProps(&#39;keyword&#39;),
    },
    {
        title: t(&quot;editPage.createAt&quot;),
        dataIndex: &#39;create_at&#39;,
        ellipsis: {
            showTitle: false,
        },
        editable: false,
        sorter: (a: any, b: any) =&gt; a.create_at - b.create_at,
        render: (create_at: number) =&gt; (
        &lt;Tooltip title={time.get_date_string_from_timestamp(create_at, &quot;YYYY-MM-DD&quot;)} placement=&#39;top&#39;&gt;
            {time.get_date_string_from_timestamp(create_at, &quot;YYYY-MM-DD&quot;)}
        &lt;/Tooltip&gt;
        ),
    },
    {
        title: t(&quot;editPage.editAt&quot;),
        dataIndex: &#39;edit_at&#39;,
        ellipsis: {
            showTitle: false,
        },
        editable: false,
        sorter: (a: any, b: any) =&gt; a.edit_at - b.edit_at,
        render: (edit_at: number) =&gt; (
        &lt;Tooltip title={time.get_date_string_from_timestamp(edit_at, &quot;YYYY-MM-DD&quot;)}&gt;
            {time.get_date_string_from_timestamp(edit_at, &quot;YYYY-MM-DD&quot;)}
        &lt;/Tooltip&gt;
        ),
    },
    {
        title: t(&quot;editPage.operation&quot;),
        dataIndex: &#39;operation&#39;,
        render: (_: any, record: CleanFilterItem) =&gt; {
          const editable = isEditing(record);
          return editable ? (
            &lt;span&gt;
              &lt;Typography.Link onClick={() =&gt; saveEditingRow(record.id)} style={{ marginRight: 8 }}&gt;
              {t(&#39;editPage.save&#39;)}
              &lt;/Typography.Link&gt;
              &lt;Popconfirm title={t(&quot;editPage.sureToCancel&quot;)} onConfirm={cancelEditTableRow}&gt;
                &lt;a&gt;{t(&#39;editPage.cancel&#39;)}&lt;/a&gt;
              &lt;/Popconfirm&gt;
            &lt;/span&gt;
          ) : (
            &lt;div&gt;
              &lt;Typography.Link disabled={editingKey !== &#39;&#39;} onClick={() =&gt; editTableRow(record)}&gt;
                {t(&#39;editPage.edit&#39;)}
              &lt;/Typography.Link&gt;
              &lt;Divider type=&quot;vertical&quot; /&gt;
              &lt;Typography.Link disabled={editingKey !== &#39;&#39;} onClick={() =&gt; removeRow(record)}&gt;
              {t(&#39;editPage.delete&#39;)}
              &lt;/Typography.Link&gt;              
            &lt;/div&gt;
          );
        },
    }
  ]

  const mergedEditColumns = edit_tabel_column.map((col) =&gt; {
    if (!col.editable) {
      return col;
    }
    return {
      ...col,
      onCell: (record: CleanFilterItem) =&gt; ({
        record,
        inputType: col.dataIndex,
        dataIndex: col.dataIndex,
        title: col.title,
        editing: isEditing(record),
      }),
    };
  })

  &lt;Form form={form} component={false}&gt;
    &lt;Table 
        components={{
          body: {
            cell: EditableCell
          }
        }}
        rowSelection={rowSelection} 
        columns={mergedEditColumns} // here comes types error
        className={style.customTable}
        dataSource={tableData} 
        pagination={{ pageSize: 5 }}
        scroll={{ y: 360 }}
        rowKey={&quot;id&quot;}
    /&gt;
  &lt;/Form&gt;

and it leads to the following errors

Type &#39;({ title: string; dataIndex: string; editable: boolean; filters?: undefined; filterSearch?: undefined; onFilter?: undefined; render?: undefined; ellipsis?: undefined; sorter?: undefined; } | { title: string; ... 7 more ...; sorter?: undefined; } | ... 6 more ... | { ...; })[]&#39; is not assignable to type &#39;(ColumnType&lt;CleanFilterItem&gt; | ColumnGroupType&lt;CleanFilterItem&gt;)[]&#39;.
  Type &#39;{ title: string; dataIndex: string; editable: boolean; filters?: undefined; filterSearch?: undefined; onFilter?: undefined; render?: undefined; ellipsis?: undefined; sorter?: undefined; } | { title: string; ... 7 more ...; sorter?: undefined; } | ... 6 more ... | { ...; }&#39; is not assignable to type &#39;ColumnType&lt;CleanFilterItem&gt; | ColumnGroupType&lt;CleanFilterItem&gt;&#39;.
    Type &#39;{ title: string; dataIndex: string; editable: boolean; filters: { text: string; value: string; }[]; filterSearch: boolean; onFilter: (value: string, record: any) =&gt; boolean; render: (state: string) =&gt; JSX.Element; ellipsis?: undefined; sorter?: undefined; }&#39; is not assignable to type &#39;ColumnType&lt;CleanFilterItem&gt; | ColumnGroupType&lt;CleanFilterItem&gt;&#39;.
      Type &#39;{ title: string; dataIndex: string; editable: boolean; filters: { text: string; value: string; }[]; filterSearch: boolean; onFilter: (value: string, record: any) =&gt; boolean; render: (state: string) =&gt; JSX.Element; ellipsis?: undefined; sorter?: undefined; }&#39; is not assignable to type &#39;ColumnType&lt;CleanFilterItem&gt;&#39;.
        Types of property &#39;onFilter&#39; are incompatible.
          Type &#39;(value: string, record: any) =&gt; boolean&#39; is not assignable to type &#39;(value: string | number | boolean, record: CleanFilterItem) =&gt; boolean&#39;.
            Types of parameters &#39;value&#39; and &#39;value&#39; are incompatible.
              Type &#39;string | number | boolean&#39; is not assignable to type &#39;string&#39;.
                Type &#39;number&#39; is not assignable to type &#39;string&#39;.ts(2322)
InternalTable.d.ts(14, 5): The expected type comes from property &#39;columns&#39; which is declared here on type &#39;IntrinsicAttributes &amp; TableProps&lt;CleanFilterItem&gt; &amp; { children?: ReactNode; } &amp; { ref?: Ref&lt;HTMLDivElement&gt; | undefined; }&#39;

I've checked this question columns type error when using a custom sorter function on Ant Design table and try add the following definition to my column, but it still fails

const edit_tabel_column: (ColumnsType&lt;CleanFilterItem&gt; &amp; {editable?: boolean}[]) = []

I'm not good at such a complex type definiation, so how should i give it a proper definition?

答案1

得分: 0

问题在于onFilter列的类型定义为value: string | number | boolean, record: Item

如果我们定义自己的onFilter类型,定义如下:
value: number, record: Item

它会抛出错误,称value: numbervalue: string | number | boolean不兼容。

解决办法是让它们具有相同的类型定义,即string | number | boolean

这是我的复制链接一旦可编辑表格列具有onFilter属性,TypeScript声称mergedColumns与columns的类型不兼容

英文:

The problem is the column onFilter type has a type definition
value: string | number | boolean, record: Item

If we define our own onFilter type with definition like
value: number, record: Item

It will throw errors, claim tha value: number is not compatiable with value: string | number | boolean.

The solution is to let them have the same type definition as string | number | boolean.

And here's my reproduction link Once on editable table columns has onFilter property, typescript claims that mergedColumns is not assignable type with columns

huangapple
  • 本文由 发表于 2023年4月19日 21:53:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76055369.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定