Skip to content

Conversation

@crishoj
Copy link

@crishoj crishoj commented Nov 20, 2025

Problem

When using t.Date() in Elysia query schemas, Eden Treaty incorrectly infers that clients should pass Date objects. However, HTTP query parameters are always strings, causing a type mismatch:

// Schema definition
.get('/metrics', ({ query }) => query, {
  query: t.Object({
    since: t.Date()
  })
})

// Current (incorrect) - TypeScript error
api.metrics.get({ query: { since: '2023-01-02T00:00:00Z' } })
//                                   ^^^^^^^^^^^^^^^^^^^^
// Error: Type 'string' is not assignable to type 'Date'

// TypeScript wants this (but doesn't work at runtime)
api.metrics.get({ query: { since: new Date('2023-01-02') } })

Solution

  • Added SerializeQueryParams<T> type helper in src/treaty2/types.ts
  • Applied transformation to regular routes (line 100)
  • Applied transformation to WebSocket subscribe routes (line 87)
  • Added type-level test in test/types/treaty2.ts

Client-side (Eden): query: { since: string }
Server-side (Elysia): query: { since: Date }

Possibly Related Issues

This PR addresses the type-level issue, while previous fixes targeted runtime serialization.

Summary by CodeRabbit

  • New Features
    • Added improved type handling for date-based query parameters, ensuring proper serialization in API requests.
    • Expanded API parameter support with better type safety for date inputs.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 20, 2025

Walkthrough

A new generic utility type SerializeQueryParams<T> is introduced to transform Date types to strings in query parameters. This type is applied to Treaty.Sign for both subscribe and non-subscribe routes, ensuring query parameters with Date values are represented as strings in the type system. A test case is added for a /date/query endpoint with a Date query parameter.

Changes

Cohort / File(s) Summary
Query parameter type serialization
src/treaty2/types.ts
Introduces SerializeQueryParams<T> generic type that maps Date to string and Date | undefined to string | undefined while preserving other types. Applied to Treaty.Sign in both subscribe route branch (Route['subscribe']['query']) and general query handling (MaybeEmptyObject<Query, 'query'>)
Type coverage for Date query parameters
test/types/treaty2.ts
Adds new GET route at api['date']['query']['get'] with query parameter since: Date. Type expectations declare query as { since: string } in parameters while response data contains { since: Date }

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • SerializeQueryParams type logic: Verify the conditional type mappings correctly handle Date, Date | undefined, and all other types across various query object structures
  • Apply transformation accuracy: Confirm the type is applied correctly in both subscribe and non-subscribe branches without introducing type inconsistencies
  • Test case validation: Ensure the test case properly reflects the intended behavior where query parameters serialize Date → string while response data remains Date

Possibly related PRs

Poem

🐰 Dates that once were wild and free,
Now strings in query land shall be,
Yet in responses, round they go—
Type magic makes the parameters flow! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: fixing type inference for Date objects in query parameters by introducing serialization logic.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/treaty2/types.ts (1)

61-69: LGTM! Type transformation correctly handles the common case.

The SerializeQueryParams type correctly transforms Date fields to string for query parameters, which aligns with HTTP query string semantics.

Limitations (acceptable for typical query parameter usage):

  • Only handles flat/shallow Date fields, not nested objects or Date arrays
  • Query parameters are typically flat structures, so this limitation is reasonable for the use case

Optional refinement:
Consider using Record<string, unknown> instead of Record<string, any> for stricter type safety, though this has minimal practical impact.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d5441e9 and aa0e5fb.

📒 Files selected for processing (2)
  • src/treaty2/types.ts (3 hunks)
  • test/types/treaty2.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/treaty2/types.ts (1)
src/types.ts (1)
  • MaybeEmptyObject (64-78)
🔇 Additional comments (3)
test/types/treaty2.ts (2)

34-38: LGTM! Clean test case for Date query parameters.

The route definition correctly demonstrates the use case: a Date type in the query schema that needs to be handled as a string at the client level.


507-535: LGTM! Type test validates the expected behavior.

The test correctly verifies that:

  1. Client-side query parameters expect since: string (appropriate for HTTP query strings)
  2. Server-side response data contains since: Date (after Elysia's t.Date() parsing)

This validates the fix achieves its goal of resolving the type mismatch.

src/treaty2/types.ts (1)

89-89: LGTM! SerializeQueryParams correctly applied to both route types.

The transformation is properly applied to:

  • WebSocket subscribe routes (line 89)
  • Regular HTTP routes (line 102)

Both applications correctly wrap the query type with SerializeQueryParams before passing to MaybeEmptyObject, ensuring Date fields are transformed to strings at the type level for all query parameters.

Also applies to: 102-102

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.

1 participant