Day 16. slate × Interfaces × CustomType

https://ithelp.ithome.com.tw/upload/images/20211001/20139359JwqC2Afvj6.png

slate 将 typescript 的型别扩充相关的内容都集合在 interfaces/custom-types.ts 这个 file 里面。

这个 file 的 code 是由一名叫 thesunny 的 contributor 针对新版 slate 处理 custom types 的修改建议。

因为在之前的版本,开发者需要在每次使用 api call 时都得重复以 generic 的形式传 custom-types ,这份 file 出现的目的正是让开发者在开发 slate project 时只需定义一次 custom-types 就能一劳永逸。

Slate Custom-Types


这里头主要功能的部分只有短短地不到 10 行,却利用了 interface 的 declaration merging 、 type 的 discriminating union 以及 unknown 的特性一次包办了整个 type customizing 所需的一切功能,笔者当初看到的时候觉得真的是太厉害了!特地拉成一整篇文章与各位读者分享。

我们先直接来看一下 custom-types.ts file 里面的 code

/**
 * Extendable Custom Types Interface
 */

type ExtendableTypes =
  | 'Editor'
  | 'Element'
  | 'Text'
  | 'Selection'
  | 'Range'
  | 'Point'
  | 'InsertNodeOperation'
  | 'InsertTextOperation'
  | 'MergeNodeOperation'
  | 'MoveNodeOperation'
  | 'RemoveNodeOperation'
  | 'RemoveTextOperation'
  | 'SetNodeOperation'
  | 'SetSelectionOperation'
  | 'SplitNodeOperation'

export interface CustomTypes {
  [key: string]: unknown
}

export type ExtendedType<
  K extends ExtendableTypes,
  B
> = unknown extends CustomTypes[K] ? B : CustomTypes[K]

ExtendableTypes 不难理解,它就是事先为可以进行扩充的 types 做好限制,在 ExtendedType 吃的第一个 generic type 有限制了它的范围必须缩限在 ExtendableTypes 之中,这也是为什麽我们在 Day11 的 Example type 范例放进 ExtendedType 里是不会过关的原因。

CustomTypes 是主要让开发者定义 custom types 的 interface ,利用 interface 可以 extend 的特性让开发者可以透过 declare module 等方式扩充。

拿 slate 提供的 example code 作为范例,引入下方的 file 後 CustomTypes 就会多了 EditorElementText 这三组 keys 的定义:

declare module 'slate' {
  interface CustomTypes {
    Editor: CustomEditor
    Element: CustomElement
    Text: CustomText | EmptyText
  }
}

最後是最精华的 ExtendedType utility ,它吃了两个 type generics 分别是:

  • K : 缩限於上方的 ExtendableTypes ,负责比对 CustomTypes 中指定的 key 类型是否被扩充定义。
  • B : 传入的 base-type ,如果对应到的 key 没有在 CustomTypes 中被扩充定义的话会原封不动地回传 B 。

让我们搭配最基本的 Text type 协助我们介绍

/** text.ts */
export interface BaseText {
  text: string
}

export type Text = ExtendedType<'Text', BaseText>

/** custom-types.ts */
export type ExtendedType<
  K extends ExtendableTypes,
  B
> = unknown extends CustomTypes[K] ? B : CustomTypes[K]
  1. 在我们将 'Text'BaseText 传入 ExtendedType 以後,它首先会确认 'Text' 是否存在於 ExtendableTypes 里。
  2. 接着进行 unknown extends CustomTypes[K] 的三元判断式,这里运用了 unknown 只会 extends unknown 这项特性,当判断结果为 true 时代表开发者未在 CustomTypes 里对 K 做扩充,回传 base-type 给 Text,反之则回传 CustomTypesK 对应到的扩充内容给 Text

最後再附上 Slate Github issue 的讨论串,笔者在深入了解以前都只是照着 slate 提供的 example code 依样画葫芦而已,一直将纳闷放在心中。希望今天的分享也能让读者们体会笔者当时备受震慑的心情 XD

到这篇为止我们的 interface/ 章节终於要画上句点了,接下来我们要先花些篇幅来聊聊 Immutable 这项议题,以及它、 Immer.js 、 Slate 之间的关系。

咱们明天见罗~


<<:  [Day 16] 阿嬷都看得懂的通用 .html 档案结构

>>:  # Day16--ARC到底是虾饺?神秘的实体化背後的秘密

[Day 29]从零开始学习 JS 的连续-30 Days---网页座标及应用

网页座标及应用 首先怎麽读取与显示座标。 座标的判断依据。 如何动态撷取浏览器宽高。 mousemo...

Javascript 传值传址&深浅拷贝

前言 因为公司前端资料已经处理成单层结构,所以都没注意到浅拷贝、深拷贝的实际差别。 在读完高手文章後...

20 - Husky - Git Hooks 工具

为了维护专案程序码的品质,我们需要对提交的代码做各式的检查(例如: Lint 、 Format 、 ...

总结 "不仅是程序码代管平台 - Github 能做些什麽?"

首先,我要先感谢老婆与家人的支持,让我有机会在 2021 年 ITHome 铁人赛完赛。其次感谢热心...

day13_Linux Arm 的文书之旅

文书工作只能用 windows 吗? 在求学过程中,作业常常要求使用微软的 office 全家桶来进...