Skip to content

fix(api): safeextend when attaching variable schemas#838

Merged
johngeorgewright merged 1 commit into
masterfrom
refinement-overrides
Feb 13, 2026
Merged

fix(api): safeextend when attaching variable schemas#838
johngeorgewright merged 1 commit into
masterfrom
refinement-overrides

Conversation

@johngeorgewright

Copy link
Copy Markdown
Collaborator

The .safeExtend() method works similarly to .extend(), but it won't let you overwrite an existing property with a non-assignable schema. In other words, the result of .safeExtend() will have an inferred type that extends the original (in the TypeScript sense).

Use .safeExtend() to extend schemas that contain refinements. (Regular .extend() will throw an error when used on schemas with refinements.)

The .safeExtend() method works similarly to .extend(), but it won't let you overwrite an existing property with a non-assignable schema. In other words, the result of .safeExtend() will have an inferred type that extends the original (in the TypeScript sense).

Use .safeExtend() to extend schemas that contain refinements. (Regular .extend() will throw an error when used on schemas with refinements.)
Copilot AI review requested due to automatic review settings February 13, 2026 15:07
@johngeorgewright johngeorgewright merged commit 54de23c into master Feb 13, 2026
7 checks passed
@johngeorgewright johngeorgewright deleted the refinement-overrides branch February 13, 2026 15:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates the variable-resolver schema attachment logic to use Zod’s .safeExtend()/safeExtend() when rebuilding object shapes, improving compatibility with schemas that include refinements and preserving “type extends original” semantics.

Changes:

  • Replace extend(...) with safeExtend(...) for ZodMiniObject shape rebuilding.
  • Replace .extend(...) with .safeExtend(...) for ZodObject shape rebuilding (introducing an as any cast to satisfy typing).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

acc.extend({
[key]: attachVariableResolver(variablesRegistry, parser),
acc.safeExtend({
[key]: attachVariableResolver(variablesRegistry, parser) as any,

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

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

as any on the value passed to acc.safeExtend() defeats the main benefit of safeExtend (type-level guarantee that the new schema is assignable to the existing property type). It would be better to preserve typing by casting to a narrower type (e.g., based on the existing parser type) or by constructing a typed extension shape first and calling safeExtend once, so TypeScript can keep key/value relationships without falling back to any.

Suggested change
[key]: attachVariableResolver(variablesRegistry, parser) as any,
[key]: attachVariableResolver(variablesRegistry, parser) as $ZodType,

Copilot uses AI. Check for mistakes.
Comment on lines 79 to 83
(acc, [key, parser]) =>
extend(acc, {
safeExtend(acc, {
[key]: attachVariableResolver(variablesRegistry, parser),
}),
objectParser,

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

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

This change is meant to fix extending object schemas that include refinements, but current tests only cover .refine() on a primitive (z.string().refine(...)) and don't exercise objectVariableResolverParser on a refined object schema (e.g., z.object({...}).refine(...) or superRefine). Please add a regression test that calls Data.create().usePayload(...) with a refined object payload and uses variables within nested properties, ensuring addRules() no longer throws during schema attachment.

Copilot uses AI. Check for mistakes.
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.

2 participants