TypeScript项目实践之 Omit 特性

14,642 阅读4分钟

前言

入职两个月以来每天都在接触 TypeScript,但其实用的还不是很好,经常踩坑。所以我接下来也会尝试着更新自己该系列文章,目的是除了巩固总结自己的所学之外,也希望能够帮助到正在学习TypeScript但没有在真实项目实践中使用过TypeScript的人们。

Omit 介绍

Omit的中文意思是 忽略 ,是 TypeScript 3.5 版本推出的特性,以下是官网的介绍

TypeScript 3.5 添加了新的 Omit 辅助类型,这个类型用来创建从原始类型中移除了某些属性的新类型。

因为是我想写的主要是在真实项目中对于该特性的实践,因此官网里的例子我就不列举了。

需求介绍

因为我所在小组负责的是偏向企业服务的,类似于后台管理,因此会遇到很多的 Table, 采用的 UI框架是 ant-design, 所以我会列举一个。

现在我们需要对表格做一个筛选功能,这会用到ant-desighTablefilterDropdown属性,如下图所示:

那么如何使用呢,还是看下面的代码吧:

  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
    filterType: true,
    filterDropdown: ({ confirm, selectedKeys, setSelectedKeys }) => (
      <DropDownList
        confirm={confirm}
        selectedKeys={selectedKeys}
        setSelectedKeys={setSelectedKeys}
      />
    ),
  }

filterDropdown 可以的值可以是一个函数,其中注意到其参数的 props 的类型是 FilterDropdownProps, 这是个什么东西呢,我们进去源码看看:

export interface FilterDropdownProps {
    prefixCls: string;
    setSelectedKeys: (selectedKeys: React.Key[]) => void;
    selectedKeys: React.Key[];
    confirm: () => void;
    clearFilters?: () => void;
    filters?: ColumnFilterItem[];
    visible: boolean;
}

可以看到FilterDropdown有很多的属性, 其中有 selectedKeyssetSelectedKeys, 这也就是为什么我们在上面使用 filterDropdown 的时候可以通过解构赋值拿到 selectedKeyssetSelectedKeys

注意点

我们看到 setSelectedKeys,其参数类型是 React.Key[] 类型的,

通过上图可以发现,这个 setSelectedKeys 只能接收一个 string 或者 number 类型的数组。

那如果我们在需求里遇到了要用string或者number类型之外的类型怎么办?

Omit 用法

上面介绍的时候提到,Omit 的意思是忽略,在这里,我们应该理解为 Omit 可以忽略某个类型的某些属性,假设我们现在想要让 setSelectedKeysselectedKeys 能接收一个非string 或者 number 类型的数组,那么我们只需使用 Omit 忽略 这两个属性,然后我们自己给这两个属性赋值新的类型是不是就可以了?

Omit <T, K>

其中 Ttype也就是类型的简写, Kkey 的简写,所以这里的意思就是忽略该类型的key属性

import { FilterDropdownProps } from 'antd/es/table'

type TagProps = {
    slug: string
    name: string
}

type MyFilterDropdownProps = Omit<FilterDropdownProps, 'selectedKeys' | 'setSelectedKeys'> & {
    selectedKeys: TagProps
    setSelectedKeys: (selectedKeys: TagProps[]) => void
}

上面这段代码,先看左边 Omit<FilterDropdownProps, 'selectedKeys' | 'setSelectedKeys'>, 这里的意思就是要忽略 FilterDropdownPropsselectedKeyssetSelectedKeys 属性,然后我们还做了一步最重要的操作,就是通过 & 符号将我们自己定义的 selectedKeyssetSelectedKeysFilterDropdownProps 剩下的属性组合起来了,最后再赋值给 MyFilterDropdownProps 类型。

那么这个时候,我们就已经将FilterDropdownProps里的 selectedKeyssetSelectedKeys 改造成了我们希望能够接收的类型。

还没结束

我相信用过filterDropdown这个属性的同学,一定都知道该属性是在 column 中使用的,column是一个对象数组,每一个对象代表一列,既然filterDropdown是用在column中的,那么我们最后要做的就是把column中的filterDropdown属性替换成我们自己定义的类型即可。

在此之前,我们先看看column里有哪些属性,上源码:

可以看到,这个ColumnType就是column 数组中每个对象可以使用的属性,其中就有 filterDropdown 属性,所以我们最后一步操作如下代码:

import React, { FC } from 'react'
import { ColumnType, FilterDropdownProps, TableProps } from 'antd/es/table'

type TagProps = {
    slug: string
    name: string
}

type MyFilterDropdownProps = Omit<FilterDropdownProps, 'selectedKeys' | 'setSelectedKeys'> & {
    selectedKeys: TagProps
    setSelectedKeys: (selectedKeys: TagProps[]) => void
}

// 注意这里原来的 FilterDropdownProps 已经被替换成我们自定义的 MyFilterDropdownProps
type MyColumnType<T> = Omit<ColumnType<T>, 'filterDropdown'> & {
    filterDropdown?: React.ReactNode | ((props: MyFilterDropdownProps) => React.ReactNode);
}

// 又因为 column 是 Table 的属性
type MyTableProps<T> = Omit<TableProps<T>, 'column'> & {
    columns?: MyColumnType<T>;
}

type User = {
    //
}

// MyTable 可以像普通的Table 一样使用, 因为其类型是我们改造过的 TableProps
// 因此 Table 可以接收的属性 MyTable 也同样可以接收
const MyTable: FC<MyTableProps<User>> = (props) => {
    const { xxx, xxx, xxx, ...restProps } = props
    
    const columns: MyColumnType<User>[] = [{
        //,
        //,
        filterDropdown: ({selectedKeys, setSelectedKeys}) => {
            // 此时的 selectedKeys 跟 setSelectedKeys 接收的类型已经被改造成 TagProps 了
            // 而不是 antd table 定义的类型了
        })
    }]
    
    return <Table {...restProps} columns={columns} />
}

其实到这里,关于 Omit的用法就讲完了,我想通过上面这几段代码,应该可以很好的说明Omit在实践当中是如何使用的。

谢谢观看小弟的文章,希望对各位有帮助。