Skip to content

Document and allow extending strict schema maps#3116

Open
joshkel wants to merge 1 commit into
hapijs:masterfrom
joshkel:extensible-schemas
Open

Document and allow extending strict schema maps#3116
joshkel wants to merge 1 commit into
hapijs:masterfrom
joshkel:extensible-schemas

Conversation

@joshkel
Copy link
Copy Markdown
Contributor

@joshkel joshkel commented May 15, 2026

I've found Joi's object's strict schema checking useful to catch errors in TypeScript projects, but it has limitations when combined with Joi extensions: when used with custom classes (such as js-joda's Temporal classes like Instant), Joi's StrictSchemaMap expects a generic Joi.ObjectSchema<Instant> instead of the schema objects returned by my extensions.

To address that, this PR uses a module-augmentable "type registry" interface that ObjectPropertiesSchema consults before falling back to its built-in chain. The trick is that the registry needs to map value types to schema types, not key names, so users key entries by an arbitrary tag and the library iterates the keys to find a matching type.

Additional notes:

  1. Ordering / precedence: Putting the custom lookup first lets users override built-ins but means a buggy augmentation can break the default mapping. Putting it last is safer but means users can't override (e.g.) Date.
  2. Subtype collisions: If two registry entries' type fields overlap (e.g. one entry's type is object and another is Instant), the mapped-type iteration yields a union of both schemas.
  3. null/undefined handling: The existing NullableType<...> checks accept T | null | undefined. This implementation strips them before comparing, matching the existing behavior.

I did not see where the preexisting strict schema validation handling was documented, so I added a section covering that to the API docs.

This uses a module-augmentable "type registry" interface that ObjectPropertiesSchema consults before falling back to its built-in chain. The trick is that the registry needs to map value types to schema types, not key names, so users key entries by an arbitrary tag and the library iterates the keys to find a matching type.

Additional notes:

1. Ordering / precedence: Putting the custom lookup first lets users override built-ins but means a buggy augmentation can break the default mapping. Putting it last is safer but means users can't override (e.g.) Date.
2. Subtype collisions: If two registry entries' type fields overlap (e.g. one entry's type is object and another is Instant), the mapped-type iteration yields a union of both schemas.
3. null/undefined handling: The existing NullableType<...> checks accept T | null | undefined. This implementation strips them before comparing, matching the existing behavior.

I did not see where the preexisting strict schema validation handling was documented, so I added a section covering that to the API docs.
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