colinhacks / zod

TypeScript-first schema validation with static type inference
https://zod.dev
MIT License
33.95k stars 1.19k forks source link

Type inference issue with extending/narrowing enum types in generic schemas #3825

Open AnzeKop opened 1 week ago

AnzeKop commented 1 week ago

I'm encountering a TypeScript error when trying to extend/narrow an enum type in a generic schema context. While TypeScript normally allows narrowing of enum types, this doesn't seem to work properly with Zod's type system.

import { z } from 'zod';

// Base schema with broader enum
const baseSchema = z.object({
gender: z.enum(["Rüde", "Hündin", "männlich", "weiblich"]).nullable(),
// ... other fields
});
// Trying to create a more specific schema with narrower enum
const dogSchema = z.object({
gender: z.enum(["Rüde", "Hündin"]).nullable(),
// ... other fields
});
// Generic interface that should accept both schemas
interface MyInterface<T extends typeof baseSchema> {
schema: T;
// ... other properties
}
// This fails with type error even though dogSchema's enum is a subset of baseSchema's enum
const implementation: MyInterface<typeof dogSchema> = {
schema: dogSchema
};

the type error probobly happens since zod is saying that

Type 'ZodEnum<["Rüde", "Hündin"]>' is not assignable to type 'ZodEnum<["Rüde", "Hündin", "männlich", "weiblich"]>

Expected Behavior

Since the enum in dogSchema is a subset of the enum in baseSchema, and TypeScript normally allows this kind of type narrowing, the implementation should type-check successfully.

Actual Behavior

TypeScript produces an error indicating that the narrower enum type is not assignable to the broader enum type when used in this generic context with Zod schemas.

Possible Solutions

One potential solution might be to add a utility type or method to Zod that explicitly handles enum narrowing in generic contexts, similar to how TypeScript handles normal enum type narrowing.

m10rten commented 1 week ago

Hi, zod does not actually know that the values are the same, does it?

Have you tried with .extend or .merge?