Skip to content

feat(Schema): preserve encodedKey across field reuse, spread, and mapFields#2198

Open
patroza wants to merge 8 commits into
Effect-TS:mainfrom
patroza:schema/encode-keys-struct-field-renames
Open

feat(Schema): preserve encodedKey across field reuse, spread, and mapFields#2198
patroza wants to merge 8 commits into
Effect-TS:mainfrom
patroza:schema/encode-keys-struct-field-renames

Conversation

@patroza
Copy link
Copy Markdown
Contributor

@patroza patroza commented May 16, 2026

Summary

In effect v3, a struct field's encoded key rename traveled with the field. In effect-smol, renames only existed as a top-level encodeKeys mapping on the struct AST, so:

  • Struct.fields.x exposed the un-renamed encoded shape
  • Spreading shared field maps lost the rename
  • mapFields / Class.mapFields dropped the rename
  • Reusing a field across structs forced you to repeat the rename in every parent

This PR moves the rename from a struct-level concern to a field-local annotation and threads it through the type system so it survives reuse, spreading, mapFields, encodeKeys, and flip ∘ flip.

Approach

Two alternatives were considered:

  1. Expose encodedFields / encodedMapFields on the struct or adding fields/mapFields to the return value of S.encodedKeys. Keeps the rename at the struct level, still does not help when a single field schema is consumed by an unrelated struct.
  2. Make the rename a property of the field schema itself. A new Schema.encodedKey("foo") combinator attaches an encodedKey annotation to the field's Key annotation bag. Struct(...) discovers those annotations at construction time and folds them into an encodeKeys(...) mapping automatically. Field reuse, spread, and mapFields then "just work" because the rename rides on the field.

Option 2 won — same author ergonomics, no new struct API, and the rename is preserved through any operation that preserves the field schema.

Type-level plumbing

A new EncodedKey extends PropertyKey parameter is appended to Bottom:

export interface Bottom<
  ...,
  out EncodedOptionality extends Optionality = "required",
  out EncodedKey extends PropertyKey = never
> { readonly "~encoded.key": EncodedKey }

Copilot AI and others added 7 commits May 16, 2026 06:52
Agent-Logs-Url: https://github.com/patroza/effect-smol/sessions/32848271-8151-4553-9929-2451da3e02ef

Co-authored-by: patroza <42661+patroza@users.noreply.github.com>
Agent-Logs-Url: https://github.com/patroza/effect-smol/sessions/4ae338a3-dc81-4aa5-a0de-1d7b81d2919a

Co-authored-by: patroza <42661+patroza@users.noreply.github.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 16, 2026

🦋 Changeset detected

Latest commit: d483e23

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 27 packages
Name Type
effect Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/vitest Patch
@effect/ai-anthropic Patch
@effect/ai-openai-compat Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/openapi-generator Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@mikearnaldi mikearnaldi requested a review from gcanti May 16, 2026 08:01
@jdharrisnz
Copy link
Copy Markdown

Nice to see this come back. Would this work on classes too or only structs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants