已发布 上游基线 bf46254 原文 ↗ 在 GitHub 编辑

从 Schema 派生 Equivalence

从 schema 结构派生并定制等价性检查。

Schema.toEquivalence 会为某个 schema 的 Type 派生出一个 Equivalence。嵌套值会按照对应的嵌套 schema 进行比较。

示例(比较 Struct)

import { Schema } from "effect"

const Person = Schema.Struct({
  name: Schema.String,
  age: Schema.Finite,
  tags: Schema.Array(Schema.String),
})

const equivalence = Schema.toEquivalence(Person)

equivalence(
  { name: "John", age: 23, tags: ["admin"] },
  { name: "John", age: 23, tags: ["admin"] },
) // => true

equivalence(
  { name: "John", age: 23, tags: ["admin"] },
  { name: "John", age: 24, tags: ["admin"] },
) // => false

对于 struct,只有 schema 中描述的字段会参与派生出的 equivalence。数组和嵌套的 struct 会递归地比较。

宽泛的 Schema

Schema.AnySchema.UnknownSchema.ObjectKeyword 以及空的 Schema.Struct({}) 都使用 Equal.equalsEqual.equals 会为对象和数组执行深层结构比较,而不是默认采用引用相等。

示例(空 Struct 的结构相等性)

import { Schema } from "effect"

const equivalence = Schema.toEquivalence(Schema.Struct({}))

equivalence({ nested: [1, 2] }, { nested: [1, 2] }) // => true

声明

声明(declaration)对于自动派生而言是不透明的。当声明需要 Equal.equals 之外的行为时,请提供一个 toEquivalence 注解。

示例(为一个类定义 Equivalence)

import { Schema } from "effect"

class User {
  constructor(
    readonly id: number,
    readonly displayName: string,
  ) {}
}

const UserSchema = Schema.instanceOf(User, {
  toEquivalence: () => (self, that) => self.id === that.id,
})

const equivalence = Schema.toEquivalence(UserSchema)

equivalence(new User(1, "Alice"), new User(1, "Alicia")) // => true

参数化的声明会在注解回调中接收为每个类型参数派生出的 equivalence。

覆盖

使用 Schema.overrideToEquivalence 可以替换为已有 schema 派生出的 equivalence。

示例(按单个字段比较 Struct)

import { Schema } from "effect"

const User = Schema.Struct({
  id: Schema.Finite,
  displayName: Schema.String,
}).pipe(Schema.overrideToEquivalence(() => (self, that) => self.id === that.id))

const equivalence = Schema.toEquivalence(User)

equivalence({ id: 1, displayName: "Alice" }, { id: 1, displayName: "Alicia" }) // => true

equivalence({ id: 1, displayName: "Alice" }, { id: 2, displayName: "Alice" }) // => false