Skip to content

Conversation

@akim-bow
Copy link
Contributor

@akim-bow akim-bow commented Dec 1, 2025

Fixes #1577

Description

I've made additional validator to support usecase of generating proper OpenAPI schema if elysia.js is to use with external tools for generating clients or documentation. I also think that elysia should have a single method for creating nullable field instead of 2 almost equally validators. That's why i marked previous one as outdated to tell a user preferred validator to use. Probably in the future older one could be removed completely, i.e., in next major release.

If i miss some usecases why Nullable was implemented in a way it is i would be happy to correct my PR.

// Old Nullable produces (non-compliant):
{ nullable: true, anyOf: [{ type: "string" }, { type: "null" }] }

// New MaybeNull produces (OpenAPI 3.0 compliant):
{ type: "string", nullable: true }

Summary by CodeRabbit

  • New Features

    • Added a MaybeNull schema modifier to define OpenAPI‑compatible nullable fields and improve nullable type handling and error messages.
    • Exposed a top-level alias for easy use in schemas.
  • Deprecations

    • Existing nullable method remains deprecated; migrate to MaybeNull for future compatibility.
  • Tests

    • Added comprehensive tests covering OpenAPI generation and runtime validation across primitives, objects, arrays, nested structures, and edge cases.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

Walkthrough

Adds a new MaybeNull type to the type system and public API (t.MaybeNull), introduces WrappedKind and TMaybeNull, updates error handling and runtime/value checks for MaybeNull, and adds tests validating OpenAPI output and runtime behavior.

Changes

Cohort / File(s) Summary
Type system entry / public API
src/type-system/index.ts
Implements ElysiaType.MaybeNull(schema), integrates runtime Value checks and SetErrorFunction/DefaultErrorFunction handling for MaybeNull, preserves wrapped-kind metadata, and exposes t.MaybeNull = ElysiaType.MaybeNull.
Type declarations
src/type-system/types.ts
Adds export const WrappedKind = Symbol('WrappedKind') and declares TMaybeNull interface with [Kind]: 'MaybeNull' and [WrappedKind] metadata.
Tests
test/type-system/maybe-null.test.ts
Adds comprehensive tests covering OpenAPI schema generation and runtime validation for MaybeNull across primitives, arrays, nested objects, null/missing fields, and invalid inputs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Pay special attention to:
    • ElysiaType.MaybeNull wrapping logic and preservation of [WrappedKind].
    • Error handling branch using SetErrorFunction and delegation to DefaultErrorFunction.
    • Runtime validation using Value to accept null and validate wrapped values.
    • Tests asserting OpenAPI 3.0 nullable semantics and schema output.

Poem

🐰 I wrap a kind with gentle care,
Null or value — I hop right through,
Keeping metadata snug and fair,
Tests patter soft as dewdrops do,
A tiny rabbit cheers for you!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a MaybeNull validator to address OpenAPI 3.0 schema compliance issues.
Linked Issues check ✅ Passed The implementation adds MaybeNull validator that produces OpenAPI 3.0-compliant nullable schemas (type + nullable flag) instead of redundant anyOf patterns, directly addressing issue #1577 requirements.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the MaybeNull validator: type definitions, implementation, error handling, and comprehensive tests for the new feature.
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

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.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 1, 2025

Open in StackBlitz

npm i https://pkg.pr.new/elysiajs/elysia@1585

commit: d99b460

Copy link
Contributor

@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: 2

🧹 Nitpick comments (1)
test/type-system/maybe-null.test.ts (1)

1-53: Expand test coverage for MaybeNull with additional types and edge cases.

The current test suite only covers MaybeNull(String()) for OpenAPI schema generation. Consider adding tests for:

  1. Other primitive types:

    • t.MaybeNull(t.Number())
    • t.MaybeNull(t.Boolean())
    • t.MaybeNull(t.Integer())
  2. Complex types:

    • t.MaybeNull(t.Object({ ... }))
    • t.MaybeNull(t.Array(t.String()))
  3. Type validation:

    • Verify that MaybeNull(Number()) rejects strings
    • Verify that MaybeNull(String()) rejects numbers
  4. Behavioral comparison:

    • Document the difference in OpenAPI schema between Nullable (union/anyOf) and MaybeNull (nullable flag)

Example additional test:

it('MaybeNull works with various types', async () => {
	const app = new Elysia().post('/', ({ body }) => body, {
		body: t.Object({
			count: t.MaybeNull(t.Number()),
			active: t.MaybeNull(t.Boolean()),
			tags: t.MaybeNull(t.Array(t.String()))
		})
	})

	const res = await app.handle(post('/', {
		count: null,
		active: true,
		tags: ['test']
	}))
	
	expect(res.status).toBe(200)
	expect(await res.json()).toEqual({
		count: null,
		active: true,
		tags: ['test']
	})
})

it('MaybeNull rejects invalid types', async () => {
	const app = new Elysia().post('/', ({ body }) => body, {
		body: t.Object({
			count: t.MaybeNull(t.Number())
		})
	})

	const res = await app.handle(post('/', {
		count: 'not a number'
	}))
	
	expect(res.status).toBe(422)
})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 27da2a7 and 77b2713.

📒 Files selected for processing (2)
  • src/type-system/index.ts (3 hunks)
  • test/type-system/maybe-null.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
test/type-system/maybe-null.test.ts (1)
src/type-system/index.ts (1)
  • t (683-683)
src/type-system/index.ts (1)
src/index.ts (2)
  • t (8126-8126)
  • Static (8245-8245)
🔇 Additional comments (5)
src/type-system/index.ts (4)

1-1: LGTM: Import addition supports MaybeNull type signature.

The Static import is correctly added to support the type signature of the new MaybeNull function.


495-497: LGTM: Clear deprecation notice with migration path.

The deprecation notice appropriately guides users to the new OpenAPI 3.0 compliant MaybeNull function and clearly indicates the timeline for removal.


672-672: LGTM: Standard exposure pattern.

Correctly exposes MaybeNull on the t object following the established pattern.


1-683: PR objectives regarding Number validation issue #1157 cannot be verified from the provided code snippet.

The review comment claims the PR states it "Fixes issue #1157" related to Number validation producing union errors, but the code changes shown only add MaybeNull and deprecate Nullable. Without access to the PR description, git history, or the full changeset, it cannot be confirmed whether:

  1. The PR actually claims to fix #1157
  2. Number validation changes exist in other files not shown here
  3. The issue #1157 description matches what the review states
  4. These changes indirectly address the stated issue

To verify this concern, provide the PR description, the related issue details, or access to the full changeset across all modified files.

test/type-system/maybe-null.test.ts (1)

5-27: LGTM: OpenAPI schema generation tests are comprehensive.

The tests correctly verify that MaybeNull produces OpenAPI 3.0 compliant schemas with nullable: true for both primitive types and object properties.

@SaltyAom
Copy link
Member

SaltyAom commented Dec 1, 2025

This is nice, one little problem is this doesn't validate the value

Lilith cri

@akim-bow akim-bow marked this pull request as draft December 1, 2025 12:10
@akim-bow
Copy link
Contributor Author

akim-bow commented Dec 1, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@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 (6)
src/type-system/types.ts (1)

143-148: TMaybeNull shape looks good; consider tightening WrappedKind’s value type.

Structurally this is fine and aligns with other tagged schemas. If you want stricter typing, [WrappedKind]: TSchema[typeof Kind] (or a dedicated alias) would more accurately reflect that you’re storing another schema’s kind rather than an arbitrary string, but it’s not required.

src/type-system/index.ts (5)

25-29: Global error-function override: good for MaybeNull, but note the global side effect.

Importing Kind, Type, and the error helpers is appropriate here, and the error override below scopes special handling to MaybeNull while delegating others to DefaultErrorFunction. Just be aware this is a global SetErrorFunction call; any user who also calls SetErrorFunction will either override or be overridden by this, so behavior will depend on import order.


83-96: MaybeNull runtime validation now correctly delegates to the wrapped schema and accepts null.

The custom type handler reconstructs the original schema via [Kind]: wrappedKind, ...schema and checks it with Value.Check, then additionally allows value === null. This addresses the earlier concern that MaybeNull only affected OpenAPI output without actually validating nulls. You might optionally short‑circuit for null first to avoid an unnecessary Value.Check, but it’s not required.

-createType<TMaybeNull>(
-	'MaybeNull',
-	({ [Kind]: kind, [WrappedKind]: wrappedKind, ...schema }, value) => {
-		return (
-			Value.Check(
-				{
-					[Kind]: wrappedKind,
-					...schema
-				},
-				value
-			) || value === null
-		)
-	}
-)
+createType<TMaybeNull>(
+	'MaybeNull',
+	({ [Kind]: kind, [WrappedKind]: wrappedKind, ...schema }, value) => {
+		if (value === null) return true
+
+		return Value.Check(
+			{
+				[Kind]: wrappedKind,
+				...schema
+			},
+			value
+		)
+	}
+)

98-105: Custom error message for MaybeNull is clear; consider still honoring per-schema errors if needed.

The SetErrorFunction override gives a nice, specific message for MaybeNull (Expected either ${error.schema.type} or null) and defers all other kinds to DefaultErrorFunction. If you intend to support schema‑level custom error messages on MaybeNull (e.g., via error in SchemaOptions), you may want to check for and prioritize error.schema.error here before falling back to the generic string.


187-190: NumericEnum generic constraint is stricter and better models numeric enums.

Constraining NumericEnum<T extends AssertNumericEnum<T>> improves type safety by ensuring the enum‑like object matches the expected TS numeric-enum shape. This should remain source‑compatible for typical enum and enum‑like objects, but it’s worth confirming that existing call sites (especially with plain object literals) still infer T without extra casts.


538-546: MaybeNull wrapper design aligns OpenAPI output with proper runtime validation; watch the default override.

The wrapper:

  • Captures the underlying [Kind] into [WrappedKind],
  • Keeps all other schema properties via ...schema,
  • Forces default: undefined and nullable: true,
  • Tags the schema as [Kind]: 'MaybeNull'.

This cleanly separates OpenAPI representation (nullable: true with the original type) from runtime behavior (handled by the custom MaybeNull type). One thing to double‑check: always overriding default to undefined will discard any default on the wrapped schema. If users expect a default value to survive through MaybeNull, you may want to only set default when it is currently undefined, or document that MaybeNull intentionally clears the default.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77b2713 and 6387023.

📒 Files selected for processing (3)
  • src/type-system/index.ts (6 hunks)
  • src/type-system/types.ts (1 hunks)
  • test/type-system/maybe-null.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/type-system/maybe-null.test.ts
🔇 Additional comments (5)
src/type-system/index.ts (5)

5-24: Additional TypeBox type imports are consistent with later usage.

JavaScriptTypeBuilder, NumberOptions, StringOptions, TEnum, and Uint8ArrayOptions are all used below (Numeric, NumericEnum, string options, Uint8Array, and t augmentation) and keep the typings aligned with TypeBox’s API.


39-52: New type imports from ./types are wired correctly.

AssertNumericEnum, ElysiaTransformDecodeBuilder, TArrayBuffer, TFile, TFiles, TMaybeNull, and WrappedKind are all referenced later and keep the public type surface coherent with the helpers in this module.


57-57: Using Value.Check for MaybeNull’s inner validation is appropriate.

Importing Value from @sinclair/typebox/value is justified by the MaybeNull implementation; it reuses TypeBox’s runtime semantics for the wrapped schema instead of re-implementing checks.


529-531: Nullable deprecation notice clearly signals the preferred MaybeNull path.

The deprecation JSDoc is explicit about OpenAPI 3.0 compliance and future removal, which should guide users to migrate gradually.


709-711: Public alias t.MaybeNull correctly forwards to ElysiaType.MaybeNull.

This keeps the API consistent with other helpers (t.Nullable, t.MaybeEmpty, etc.) and exposes MaybeNull on the familiar t builder surface.

@akim-bow
Copy link
Contributor Author

akim-bow commented Dec 1, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@akim-bow
Copy link
Contributor Author

akim-bow commented Dec 1, 2025

@coderabbitai review PR description

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch the actual PR description and details
gh pr view 1585 --repo elysiajs/elysia --json title,body,number,url,state

# Fetch the linked issue details
gh issue view 1157 --repo elysiajs/elysia --json title,body,number,url,state,labels

Length of output: 3554


🏁 Script executed:

#!/bin/bash
# Fetch issue #1577 to verify the correct issue linkage
gh issue view 1577 --repo elysiajs/elysia --json title,body,number,url,state,labels

Length of output: 2852


🏁 Script executed:

#!/bin/bash
# Read the test file to check validation tests
cat test/type-system/maybe-null.test.ts

# Read the implementation to check validation logic
cat src/type-system/index.ts | grep -A 30 "MaybeNull"

Length of output: 7476


@akim-bow, I've reviewed the PR description and it's well-written overall! Here's my assessment:

✅ What's Good

  1. Correct issue reference: Links to t.Nullable() produces non-compliant OpenAPI 3.0 schema with redundant anyOf + nullable #1577 which accurately describes the OpenAPI compliance problem
  2. Clear motivation: Explains the goal of generating proper OpenAPI 3.0 schemas for external tooling
  3. Thoughtful deprecation approach: Marks old Nullable as deprecated rather than breaking change
  4. Asks for feedback: Shows openness to corrections on use-cases

💡 Suggested Improvements

  1. Address validation concern: SaltyAom commented that it "doesn't validate the value", but looking at the implementation and tests, validation does work correctly. Consider adding a note in the description:

    "The MaybeNull validator maintains full runtime validation, accepting either null or a value matching the wrapped schema type."

  2. Show the difference: Add a before/after schema example to make the improvement clearer:

    // Old Nullable produces (non-compliant):
    { nullable: true, anyOf: [{ type: "string" }, { type: "null" }] }
    
    // New MaybeNull produces (OpenAPI 3.0 compliant):
    { type: "string", nullable: true }
  3. Clarify OpenAPI version: Explicitly mention this targets OpenAPI 3.0 compliance (as issue t.Nullable() produces non-compliant OpenAPI 3.0 schema with redundant anyOf + nullable #1577 states)

The description is accurate and the PR correctly addresses the linked issue. The comprehensive test suite in test/type-system/maybe-null.test.ts demonstrates that validation works properly for strings, numbers, objects, arrays, and null values.

Copy link
Contributor

@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 (2)
src/type-system/index.ts (2)

99-106: Improve error message generation for MaybeNull.

The error message uses error.schema.type, which may be undefined for complex schemas, resulting in messages like "Expected either undefined or null". Additionally, referencing the MaybeNull wrapper's type rather than the wrapped schema's semantics may be confusing.

Consider using the WrappedKind to generate more meaningful error messages:

 SetErrorFunction((error) => {
 	switch (error.schema[Kind]) {
 		case 'MaybeNull':
-			return `Expected either ${error.schema.type} or null`
+			const wrappedKind = error.schema[WrappedKind] || error.schema.type || 'value'
+			return `Expected ${wrappedKind.toLowerCase()} or null`
 		default:
 			return DefaultErrorFunction(error)
 	}
 })

This produces clearer messages like "Expected string or null" or "Expected number or null" instead of "Expected either string or null".


539-539: Consider returning TMaybeNull for better type safety.

The function returns TSchema, which loses the specific TMaybeNull type information. While this maintains flexibility, returning TMaybeNull would provide better type inference.

-MaybeNull: <T extends TSchema>({ [Kind]: kind, ...schema }: T): TSchema => {
+MaybeNull: <T extends TSchema>({ [Kind]: kind, ...schema }: T): TMaybeNull => {

This change is optional and depends on whether downstream code relies on the generic TSchema type.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6387023 and 327e234.

📒 Files selected for processing (2)
  • src/type-system/index.ts (6 hunks)
  • test/type-system/maybe-null.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/type-system/maybe-null.test.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/type-system/index.ts (2)
src/type-system/utils.ts (1)
  • createType (29-36)
src/type-system/types.ts (2)
  • TMaybeNull (145-148)
  • WrappedKind (143-143)
🔇 Additional comments (6)
src/type-system/index.ts (6)

1-57: LGTM!

The new imports (DefaultErrorFunction, SetErrorFunction, Value, TMaybeNull, WrappedKind) are all properly used in the MaybeNull implementation.


188-206: LGTM!

Adding the type parameter T extends AssertNumericEnum<T> improves type safety for NumericEnum by enforcing that the enum values are numeric, aligning with TypeBox conventions.


711-711: LGTM!

The export follows the established pattern for Elysia type extensions.


539-547: Fix default value override in MaybeNull.

Line 543 sets default: undefined, which overrides any existing default from the input schema. For example, t.MaybeNull(t.String({ default: 'hello' })) will lose the 'hello' default.

Apply this diff to preserve the original default when present:

 MaybeNull: <T extends TSchema>({ [Kind]: kind, ...schema }: T): TSchema => {
 	return {
 		[Kind]: 'MaybeNull',
 		[WrappedKind]: kind,
-		default: undefined,
 		...schema,
 		nullable: true
 	} as unknown as TMaybeNull
 },

By removing default: undefined before spreading ...schema, any existing default will be preserved. If no default exists, it will remain undefined naturally.

Likely an incorrect or invalid review comment.


530-532: Clarify the OpenAPI version context in the deprecation notice.

The deprecation comment states "Use MaybeNull instead which is OpenAPI 3.0 compliant", but doesn't explain the rationale. Confirm that this library prioritizes OpenAPI 3.0 compatibility (where nullable: true is the standard) over OpenAPI 3.1 alignment (which uses JSON Schema-style type unions). If compatibility with OpenAPI 3.0 is the design goal, make that explicit; otherwise, clarify what other requirement drives deprecating Nullable in favor of MaybeNull.

Also verify that the function's return type on line 539 is declared as TSchema rather than TMaybeNull, which would lose type information.


83-97: Verify that Value.Check from TypeBox properly handles custom types registered via TypeRegistry.

The runtime validator reconstructs a schema with the wrapped kind and validates it using Value.Check. However, TypeBox's Value.Check may not automatically recognize custom types registered through TypeRegistry (such as UnionEnum, ArrayBuffer, Files, etc.). When MaybeNull wraps these custom types, the validation could fail because Value.Check doesn't have access to the custom validator functions.

Consider whether the validation should use an alternative approach that respects TypeRegistry entries. If Value.Check is confirmed to support custom types, add a test case with t.MaybeNull(t.UnionEnum([...])) or similar custom types to prevent regressions.

@akim-bow akim-bow marked this pull request as ready for review December 1, 2025 17:32
Copy link
Contributor

@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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 327e234 and 1851330.

📒 Files selected for processing (2)
  • src/type-system/index.ts (6 hunks)
  • test/type-system/maybe-null.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/type-system/maybe-null.test.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/type-system/index.ts (2)
src/type-system/utils.ts (1)
  • createType (29-36)
src/type-system/types.ts (3)
  • TMaybeNull (145-148)
  • WrappedKind (143-143)
  • AssertNumericEnum (249-257)
🪛 GitHub Actions: Build and Test
src/type-system/index.ts

[error] 103-103: TypeScript error TS2538: Type 'unique symbol' cannot be used as an index type.

🔇 Additional comments (4)
src/type-system/index.ts (4)

1-58: LGTM!

The new imports support the MaybeNull functionality correctly: Value enables runtime validation, and the error handling imports enable custom error messages.


84-98: LGTM!

The runtime validation correctly accepts null values and validates non-null values against the wrapped schema. This addresses the concern from the previous review about runtime null validation.


531-548: LGTM!

The deprecation notice is clear, and the MaybeNull implementation correctly preserves the original schema while setting nullable: true for OpenAPI 3.0 compliance. The use of WrappedKind to store the original Kind enables proper runtime validation.


712-712: LGTM!

The export follows the established pattern for exposing type helpers on the t API surface.

@akim-bow
Copy link
Contributor Author

akim-bow commented Dec 1, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@akim-bow
Copy link
Contributor Author

akim-bow commented Dec 1, 2025

@SaltyAom yeap, i thought Typebox magically checks this and i messed up with tests.
Now everything should be correct, please review once more.

This is nice, one little problem is this doesn't validate the value

Copy link
Contributor

@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 (3)
src/type-system/index.ts (3)

84-98: MaybeNull validator now correctly validates both null and the wrapped schema.

The MaybeNull TypeRegistry entry short-circuits null and delegates non-null values to Value.Check on the underlying schema reconstructed from [WrappedKind], which fixes the earlier “schema-only, no runtime validation” issue and keeps behavior consistent with other TypeBox-driven checks. If this ever becomes a hot path, you might later consider caching/compiling the wrapped schema once instead of calling Value.Check directly each time, but this is fine as-is.


100-107: Global TypeBox error handler override is correct but may surprise consumers.

The custom branch for Kind === 'MaybeNull' looks good and the cast to TMaybeNull when reading [WrappedKind] resolves the previous TS compile error. However, SetErrorFunction is a global override for the entire TypeBox error pipeline; importing this module will change error formatting for any other TypeBox usage in the same process. If users are also customizing TypeBox errors elsewhere, whichever runs last wins. Please confirm this global override is intentional for Elysia, or consider scoping/customizing errors inside Elysia’s own error handling rather than at the library-global TypeBox level.


531-538: Nullable deprecation messaging is clear; consider mirroring on t.Nullable alias.

The @deprecated JSDoc on ElysiaType.Nullable clearly points users to MaybeNull and notes removal in the next major. Since t.Nullable is also part of the public surface, you may want to ensure it surfaces the same deprecation hint in editor/IDE tooling (e.g., via d.ts comments or a mirrored JSDoc on the alias) so consumers see consistent guidance whichever entry point they use.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1851330 and d99b460.

📒 Files selected for processing (1)
  • src/type-system/index.ts (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/type-system/index.ts (2)
src/type-system/utils.ts (1)
  • createType (29-36)
src/type-system/types.ts (3)
  • TMaybeNull (145-148)
  • WrappedKind (143-143)
  • AssertNumericEnum (249-257)
🔇 Additional comments (3)
src/type-system/index.ts (3)

189-207: NumericEnum helper is consistent and enforces strict numeric enum values.

The NumericEnum implementation correctly constrains T via AssertNumericEnum<T>, compiles a Type.Enum schema, and uses a Transform to accept both numeric strings (via format: 'numeric') and numbers while decoding strictly to a valid enum member (rejecting NaN and out-of-range values via compiler.Check). This aligns well with the existing Numeric helper and looks sound.


540-548: MaybeNull builder wiring with WrappedKind and nullable: true looks correct.

ElysiaType.MaybeNull preserves the original schema (including any default), stores its original [Kind] into [WrappedKind], replaces [Kind] with 'MaybeNull', and forces nullable: true. Combined with the createType<TMaybeNull>('MaybeNull', ...) validator above, this gives OpenAPI 3.0–style nullable output while still validating null and non-null values against the wrapped schema. The object spread order also correctly lets the original default override the interim default: undefined.


711-713: Public t.MaybeNull alias is correctly exposed alongside t.Nullable.

Wiring t.MaybeNull = ElysiaType.MaybeNull matches the pattern used for the other helpers and ensures the new API is available from the primary t namespace without breaking existing t.Nullable callers.

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.

t.Nullable() produces non-compliant OpenAPI 3.0 schema with redundant anyOf + nullable

2 participants