使用 ts + mobx 开发的时候,有时候会遇到我们定义了可枚举的联合类型的情况,但是 mobx 自带的 types 默认不支持可枚举的联合类型,怎么办呢?
类型定义
比如此时我们有可枚举的联合类型如下
1 | type TKind = 0 | 1 | 2 |
如果在 mobx 定义中使用 types.number
肯定是不对的,类型提示对不上
这时我们可以使用 types 提供的 types.custom
方法来构造自定义的 types
types.custom
跳转到方法原型,我们可以看到该方法要求我们传入一组泛型和一个 option
该泛型要求传入两个类型,表示这个 types 执行的是从类型 T 到类型 P 的转换
该 option 包含 5 个必填字段
- name : string,表示这个新 types 的 name,似乎可以重复,但最好还是不要重复
- fromSnapshot,表示如何将类型 T 的值转换为类型 P 的值
- toSnapshot,表示如何将类型 P 的值转换为类型 T 的值
- isTargetType,表示传入的类型 T 的值能否转换为类型 P 的值
- getValidationMessage,表示 isTargetType 返回 false 时,报错的信息是什么
但我们只想定义一个类型,这时怎么平衡 T 和 P 的关系呢?
我们可以看看 types 的实际返回值
types 的返回值
举例,比如 types.number
或 types.string
这些形如 types.<T>
的 types,它们都返回 ISimpleType<T>
而 ISimpleType<T>
又 extends IType<T, T, T>
,所以最终返回的是 IType<T, T, T>
我们只需要构造出能返回 IType<T, T, T>
的 types 即可
而 types.custom
的原型如下
1 | declare function custom<S, T>(options: CustomTypeOptions<S, T>): IType<S | T, S, T>; |
可见当我们向 types.custom
填入的泛型为 <T, T>
时,该方法就会返回 IType<T, T, T>
,就可以达到我们的目标
获得自定义 types
有了如上类型推断,我们容易得到这么一个函数
1 | const customType = <T>({ |
对于上述 option 中的 5 个字段,我们可以做如下处理
- name 要求调用方传入
- fromSnapshot、toSnapshot 因为类型一致,所以均可以直接返回自身
- 因为我们的目标是可枚举的联合类型,而可枚举的联合类型是可以算出符合条件的值域的,所以要求调用方传入
acceptedValue
数组以辅助判断 - 报错信息就比较随意了,随便写写即可。此处因为我们要求
acceptedValue
必须是个数组,所以必然有toString
方法可以调用
定义自定义 types
有了方便的获取新 types 的函数,我们就可以动手了
对于本文开头的定义,我们可以写为如下形式
1 | type TKind = 0 | 1 | 2 |
之后就可以像默认的 types 一样使用了,示例如下
1 | const model = types.model("store").props({ |
都会有形如 ISimpleType<T>
的 ts 提示
感谢阅读