Skip to content

fix(zod): properly infer scalar array types#2500

Open
haltcase wants to merge 5 commits intozenstackhq:devfrom
haltcase:fix/zod-scalar-array-types
Open

fix(zod): properly infer scalar array types#2500
haltcase wants to merge 5 commits intozenstackhq:devfrom
haltcase:fix/zod-scalar-array-types

Conversation

@haltcase
Copy link

@haltcase haltcase commented Mar 19, 2026

Closes #2499

I haven't added a test case yet because the current zmodel used for testing the zod package specifies sqlite which doesn't support array types.

Edit: I've now added a test case but it required switching the provider to postgresql and regenerating the schema. Let me know if that's not desired.

Summary by CodeRabbit

  • Refactor

    • Internal type composition improved so scalar fields declared as arrays are treated as arrays before optional/nullable handling.
  • Tests

    • Added test coverage for scalar array fields (example: Post.tags inferred as string[] for create/update).
    • Updated test schema to use PostgreSQL and include a tags array on the Post model.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1f88b2a3-0091-46f8-a24f-759898d4266f

📥 Commits

Reviewing files that changed from the base of the PR and between 5f4c0db and 03b35b9.

📒 Files selected for processing (2)
  • packages/zod/src/types.ts
  • packages/zod/test/factory.test.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/zod/test/factory.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/zod/src/types.ts

📝 Walkthrough

Walkthrough

Updated internal Zod type composition to ensure scalar array fields are represented as Zod arrays; added a tags String[] field to test schemas and extended tests to assert the array-typed inference. Provider in test schema changed from sqlite to postgresql.

Changes

Cohort / File(s) Summary
Type definitions
packages/zod/src/types.ts
Scalar field Zod mapping is now conditionally wrapped with ZodArrayIf<..., FieldIsArray<...>> before optional/nullable/optional-wrapping, ensuring scalar arrays produce z.ZodArray<...> types. Review focus: conditional wrapping logic and type inference paths.
Tests
packages/zod/test/factory.test.ts
Added tags array to validPost fixture and updated type assertions to expect Post['tags'] as string[]; added create/update schema inference checks for tags.
Test schema (TS)
packages/zod/test/schema/schema.ts
Changed provider from sqlitepostgresql and added tags metadata to Post as { name: "tags", type: "String", array: true }.
Test schema (zmodel)
packages/zod/test/schema/schema.zmodel
Switched datasource provider to postgresql, added Post.tags String[], and applied formatting/spacing adjustments to some model fields (formatting-only).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇
I nudged the maps where types went astray,
Wrapped lone strings so arrays could play,
Added some tags, tidy and spry,
Types and runtime now wink eye-to-eye,
🥕✨

🚥 Pre-merge checks | ✅ 5
✅ 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 accurately and concisely describes the main fix: properly inferring scalar array types in the Zod package, which directly addresses issue #2499.
Linked Issues check ✅ Passed The PR fully addresses issue #2499 by adding ZodArrayIf wrapping for scalar fields in GetModelFieldsShape, GetModelCreateFieldsShape, and GetModelUpdateFieldsShape to properly infer z.ZodArray types.
Out of Scope Changes check ✅ Passed The only out-of-scope changes are necessary schema updates (sqlite→postgresql, adding tags field) to enable testing of array types, which is directly related to validating the fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Required to support list types

Regenerated schema with:

`pnpm --package=@zenstackhq/cli dlx zen generate --schema ./test/schema/schema.zmodel --output ./test/schema --generate-models=false --generate-input=false`
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/zod/src/types.ts (1)

53-76: ⚠️ Potential issue | 🟡 Minor

Both GetModelCreateFieldsShape and GetModelUpdateFieldsShape need the ZodArrayIf wrapper for consistent array type inference.

These types were missing the same fix applied to GetModelFieldsShape. While runtime validation works correctly (the factory's applyCardinality method properly wraps schemas with .array()), the TYPE definitions don't reflect this, causing incorrect TypeScript type inference for scalar array fields in create/update operations.

Apply the suggested fixes to ensure proper type inference across all shape types.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/zod/src/types.ts` around lines 53 - 76, Wrap the mapped field Zod
schema with ZodArrayIf in both GetModelCreateFieldsShape and
GetModelUpdateFieldsShape like you did in GetModelFieldsShape: replace
MapModelFieldToZod<Schema, Model, Field> with
ZodArrayIf<MapModelFieldToZod<Schema, Model, Field>, /* same array-condition
used in GetModelFieldsShape */> so the existing wrappers (ZodOptionalIf,
ZodOptionalAndNullableIf, z.ZodOptional) continue to apply to the array-aware
schema; update both GetModelCreateFieldsShape and GetModelUpdateFieldsShape
declarations accordingly, keeping the other conditional filters
(FieldIsRelation, FieldIsComputed, FieldIsDelegateDiscriminator) and utilities
(ModelFieldIsOptional, FieldHasDefault) intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/zod/src/types.ts`:
- Around line 53-76: Wrap the mapped field Zod schema with ZodArrayIf in both
GetModelCreateFieldsShape and GetModelUpdateFieldsShape like you did in
GetModelFieldsShape: replace MapModelFieldToZod<Schema, Model, Field> with
ZodArrayIf<MapModelFieldToZod<Schema, Model, Field>, /* same array-condition
used in GetModelFieldsShape */> so the existing wrappers (ZodOptionalIf,
ZodOptionalAndNullableIf, z.ZodOptional) continue to apply to the array-aware
schema; update both GetModelCreateFieldsShape and GetModelUpdateFieldsShape
declarations accordingly, keeping the other conditional filters
(FieldIsRelation, FieldIsComputed, FieldIsDelegateDiscriminator) and utilities
(ModelFieldIsOptional, FieldHasDefault) intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b733e876-e054-4103-845d-a68d36aa91bc

📥 Commits

Reviewing files that changed from the base of the PR and between 00768de and 7d1429c.

📒 Files selected for processing (1)
  • packages/zod/src/types.ts

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.

@zenstackhq/zod scalar array types are incorrect

1 participant