toTaggedUnion 怎么给已有联合加 match 和 guards?
Schema.Union([A, B]) 能解码,但拿到值之后你还得自己写 if (x._tag === "A"),少处理一个成员编译器也不会提醒。更麻烦的是,有些联合的判别字段根本不叫 _tag,比如 DOM 事件常见的 kind。
把联合 pipe 给 Schema.toTaggedUnion(key),key 写判别字段名,就能得到和 Schema.TaggedUnion 同样的 match、guards、isAnyOf、matchOrElse,外加 discriminants。
它和 Effect 里怎么用 Schema.TaggedUnion 定义判别联合?讲的是同一套工具,区别只在起点:后者从字段记录一次生成,这里是增强已有的联合。下面看几种典型情形。
怎么给已有的 Union 加上 match?
import { Schema } from "effect"
const A = Schema.TaggedStruct("A", { v: Schema.Number })
const B = Schema.TaggedStruct("B", { s: Schema.String })
const U = Schema.Union([A, B]).pipe(Schema.toTaggedUnion("_tag"))
console.log(U.match({ _tag: "A", v: 1 }, { A: (a) => a.v, B: (b) => b.s.length })) // 1
console.log(U.discriminants) // [ 'A', 'B' ]discriminants 是所有判别值的列表。match 的用法和 TaggedUnion 一样:传 (value, cases) 直接求值,分支参数类型已经收窄到对应成员。
判别字段不叫 _tag 怎么办?
const UiEvent = Schema.Union([
Schema.Struct({ kind: Schema.Literal("click"), x: Schema.Number }),
Schema.Struct({ kind: Schema.Literal("key"), code: Schema.String })
]).pipe(Schema.toTaggedUnion("kind"))
console.log(UiEvent.match({ kind: "key", code: "a" }, { click: (c) => c.x, key: (k) => k.code })) // a判别字段可以是任意名字,把名字传给 toTaggedUnion 即可,match 的分支名就是各成员该字段的字面量值。
判别值重复会怎样?
try {
// @ts-expect-error 判别值重复
Schema.Union([A, A]).pipe(Schema.toTaggedUnion("_tag"))
} catch (e) {
console.log(String(e)) // Error: Duplicate discriminant: A
}判别值必须唯一。重复在编译期被拒绝,运行时也会抛 Duplicate discriminant,所以你不会得到一个「看起来能用、实际有一个分支永远匹配不到」的联合。
嵌套的联合会被展平吗?
const Nested = Schema.Union([U, Schema.TaggedStruct("C", {})]).pipe(Schema.toTaggedUnion("_tag"))
console.log(Nested.discriminants) // [ 'A', 'B', 'C' ]会。嵌套的 Union 被展平成同一层,discriminants 是 A、B、C,所以可以把已经增强过的联合当成员再组合。
什么时候用 toTaggedUnion,什么时候用 TaggedUnion?
两者的区别只在起点。需要保留各成员的独立命名(比如要单独导出 Paid 的 Schema 给别处复用),或者成员是已有的 Schema、判别字段不叫 _tag,用 toTaggedUnion;一次性的小联合,用 TaggedUnion。
成员如果是 Schema.TaggedClass,也是用 toTaggedUnion 串起来,但守卫会变成 instanceof 语义,见 Schema.Class、Opaque 和 TaggedUnion 怎么选?。
版本是 effect 4.0.5。文中代码在 strict 加exactOptionalPropertyTypes下编译并运行过,相关 API 的 JSDoc 都标注为@stability stable。