Skip to content

Ts 实现 Optional 来避免类型重复定义

需求场景以及存在的问题

现有一个文章的类型 和一个创建文章的方法

typescript
interface Article {
  title: string;
  content: string;
  author: string;
  date: Date;
  readCount: number;
}

function createArticle(article: Article) {}

在创建文章的时候,传的参数与Article有区别,有些参数是可选的,有些参数又是必须的

此时,常规的做法是新创建一个CreateArticle类型,例如:

typescript
interface CreateArticle {
  title: string;
  content: string;
  author: string;
  date?: Date;
  readCount?: number;
}

但是你会发现,CreateArticleArticle两个类型的字段都长一样,只是CreateArticle有部分字段是可选的,有如下一些问题:

  • ArticleCreateArticle类型字段有很多重复的部分,需要些很多重复代码
  • Article新增字段或者修改字段名,CreateArticle也需要同步更改,维护困难

因此,我们希望有一中方式,来根据Article算出CreateArticle,这就是下面要说的 Optional

Optional 类型工具的实现

假设 Optional 的使用方式为:

typescript
type CreateArticle = Optional<Article, "date" | "readCount">;

得到的 CreateArticle 类型就是 date 和 readCount 是可选的参数,其余为必选的参数,具体实现如下:

typescript
type Optional<T, k extends keyof T> = Omit<T, k> & Partial<Pick<T, k>>;

效果展示

Optional

实现细节解释

  • Optional<T, k extends keyof T>泛型,T 为原始的类型,后面 k extends keyof T表示 K 来自于 T 中的字段,也是一个约束,不至于让传进来的字段是乱写的
  • Omit<T, k>,Omit 是 TS 引擎自带工具,作用是将 T 里面的 K 字段统统扔掉
  • Pick<T, k>,Pick 也是 TS 引擎自带工具,作用刚好和 Omit 相反,是将 T 里面所有 K 字段挑选出来
  • Partial<O>,Partial 是 TS 引擎自带工具,的作用是将 O 类型所有字段都变成可选的
  • & 作用是联合类型,两个类型取交并集