可辨识联合类型
在开始之前我们要先搞清楚两个概念「类型字面量」与「字面量类型」,因为会在可辨识联合类型的学习中用到类型字面量的特性。
这看起来非常绕,但是「类型字面量」与「字面量类型」的关系就如同雷锋和雷峰塔一样,它们只是名字有些像,所以容易造成混淆,所以我们专门把两者放在同一节,主要聊一下两者的不同。
字面量类型
字面量( Literal Type
)主要分为 真值字面量类型( boolean literal types
)、数字字面量类型( numeric literal types
)、枚举字面量类型( enum literal types
)、大整数字面量类型( bigInt literal types
)和字符串字面量类型( string literal types
)。
const a: 2333 = 2333 // ok const ab : 0b10 = 2 // ok const ao : 0o114 = 0b1001100 // ok const ax : 0x514 = 0x514 // ok const b : 0x1919n = 6425n // ok const c : 'xiaomuzhu' = 'xiaomuzhu' // ok const d : false = false // ok const g: 'github' = 'pronhub' // 不能将类型“"pronhub"”分配给类型“"github"”
字面量类型的要和实际的值的字面量一一对应,如果不一致就会报错,比如最后一个例子中字面量类型是 github
,但是值却是 pronhub
,这就会产生报错。
当字面量类型与联合类型结合的时候,用处就显现出来了,它可以模拟一个类似于枚举的效果:
type Direction = 'North' | 'East' | 'South' | 'West'; function move(distance: number, direction: Direction) { // ... }
类型字面量
类型字面量( Type Literal
) 不同于字面量类型( Literal Type
),它跟 JavaScript
中的对象字面量的语法很相似:
type Foo = { baz: [ number, 'xiaomuzhu' ]; toString(): string; readonly [Symbol.iterator]: 'github'; 0x1: 'foo'; "bar": 12n; };
你会发现这个结构跟 interface
也有点相似,我们在类型别名那一节讲过,在一定程度上类型字面量可以代替接口。
可辨识联合类型
我们先假设一个场景,现在有两个功能,一个是创建用户即 create
,一个是删除用户即 delete
.
我们先定义一下这个接口,由于创建用户不需要 id
,是系统随机生成的,而删除用户是必须用到 id
的,那么代码如下:
interface Info { username: string } interface UserAction { id?: number action: 'create' | 'delete' info: Info }
上面的接口是不是有什么问题?
是的,当我们创建用户时是不需要 id
的,但是根据上面接口产生的情况,以下代码是合法的:
const action:UserAction = { action:'create', id: 111, info: { username: 'xiaomuzhu' } }
但是我们明明不需要 id
这个字段,因此我们得用另外的方法,这就用到了上面提到的「类型字面量」了:
type UserAction = | { id: number action: 'delete' info: Info } | { action: 'create' info: Info }
这似乎完美解决了,那么我们创建一个函数分别处理 create
和 delete
两者情况,两者的不同之处就在于一个有 id
另一个没 id
这个字段:
const UserReducer = (userAction: UserAction) => { console.log(userAction.id) ... }
我们发现在编写过程中 IDE 就报错了:
类型别名 UserAction
是有两个类型字面量联合而成的,我们不知道其中传入的是有没有 id
字段的那个类型字面量,因此我们需要找到方法区分出到底是哪个类型字面量。
大家有没有想到最开始提到的「字面量类型」,它的特性不就是唯一性吗?这就是区分两者的钥匙:
const UserReducer = (userAction: UserAction) => { switch (userAction.action) { case 'delete': console.log(userAction.id); break; default: break; } }
我们上面提到了 userAction.action
就是辨识的关键,被称为可辨识的标签,我们发现上面这种模式要想实现必须要三个要素:
- 具有普通的单例类型属性—可辨识的特征,上文中就是
delete
与create
两个有唯一性的字符串字面量 - 一个类型别名包含联合类型
- 类型守卫的特性,比如我们必须用
if switch
来判断userAction.action
是属于哪个类型作用域即delete
与create
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论