Skip to main content
Glama
partial-eq.md4.03 kB
# PartialEq The `PartialEq` macro generates an `equals()` method for field-by-field structural equality comparison. This is analogous to Rust's `PartialEq` trait, enabling value-based equality semantics instead of reference equality. ## Generated Output | Type | Generated Code | Description | |------|----------------|-------------| | Class | `classNameEquals(a, b)` + `static equals(a, b)` | Standalone function + static wrapper method | | Enum | `enumNameEquals(a: EnumName, b: EnumName): boolean` | Standalone function using strict equality | | Interface | `interfaceNameEquals(a: InterfaceName, b: InterfaceName): boolean` | Standalone function comparing fields | | Type Alias | `typeNameEquals(a: TypeName, b: TypeName): boolean` | Standalone function with type-appropriate comparison | ## Comparison Strategy The generated equality check: 1. **Identity check**: `a === b` returns true immediately 2. **Field comparison**: Compares each non-skipped field ## Type-Specific Comparisons | Type | Comparison Method | |------|-------------------| | Primitives | Strict equality (`===`) | | Arrays | Length + element-by-element (recursive) | | `Date` | `getTime()` comparison | | `Map` | Size + entry-by-entry comparison | | `Set` | Size + membership check | | Objects | Calls `equals()` if available, else `===` | ## Field-Level Options The `@partialEq` decorator supports: - `skip` - Exclude the field from equality comparison ## Example ```typescript before /** @derive(PartialEq, Hash) */ class User { id: number; name: string; /** @partialEq({ skip: true }) @hash({ skip: true }) */ cachedScore: number; } ``` ```typescript after class User { id: number; name: string; cachedScore: number; static equals(a: User, b: User): boolean { return userEquals(a, b); } static hashCode(value: User): number { return userHashCode(value); } } export function userEquals(a: User, b: User): boolean { if (a === b) return true; return a.id === b.id && a.name === b.name; } export function userHashCode(value: User): number { let hash = 17; hash = (hash * 31 + (Number.isInteger(value.id) ? value.id | 0 : value.id .toString() .split('') .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) | 0; hash = (hash * 31 + (value.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) | 0; return hash; } ``` ## Equality Contract When implementing `PartialEq`, consider also implementing `Hash`: - **Reflexivity**: `a.equals(a)` is always true - **Symmetry**: `a.equals(b)` implies `b.equals(a)` - **Hash consistency**: Equal objects must have equal hash codes To maintain the hash contract, skip the same fields in both `PartialEq` and `Hash`: ```typescript before /** @derive(PartialEq, Hash) */ class User { id: number; name: string; /** @partialEq({ skip: true }) @hash({ skip: true }) */ cachedScore: number; } ``` ```typescript after class User { id: number; name: string; cachedScore: number; static equals(a: User, b: User): boolean { return userEquals(a, b); } static hashCode(value: User): number { return userHashCode(value); } } export function userEquals(a: User, b: User): boolean { if (a === b) return true; return a.id === b.id && a.name === b.name; } export function userHashCode(value: User): number { let hash = 17; hash = (hash * 31 + (Number.isInteger(value.id) ? value.id | 0 : value.id .toString() .split('') .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0))) | 0; hash = (hash * 31 + (value.name ?? '').split('').reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0)) | 0; return hash; } ```

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/macroforge-ts/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server