How to use Zod schema with existing TypeScript interface? #2796
-
I see Zod described as a "TypeScript-first" library but am struggling to figure out how to actually integrate it with my TypeScript definitions. Is there a way to pass a TypeScript interface to my Zod schema as a generic and have my linter tell me if they're not compatible? This is how it looks in Yup: import { object, number, string, ObjectSchema } from 'yup';
interface Person {
name: string;
age?: number;
sex: 'male' | 'female' | 'other' | null;
}
// will raise a compile-time type error if the schema does not produce a valid Person
const schema: ObjectSchema<Person> = object({
name: string().defined(),
age: number().optional(),
sex: string<'male' | 'female' | 'other'>().nullable().defined(),
});
// ❌ errors:
// "Type 'number | undefined' is not assignable to type 'string'."
const badSchema: ObjectSchema<Person> = object({
name: number(),
}); I found discussion here and here but didn't see any solution I could understand, or relied on codegen and external libraries. I think something like this might work? But it's very boilerplatey and I don't see anything like this in the docs: interface Person {
name: string;
age?: number;
sex: "male" | "female" | "other" | null;
}
const zodSchema = z.object({
name: z.string(),
age: z.number().optional(),
sex: z.enum(["male", "female", "other"]).nullable(),
});
type InferredPerson = z.infer<typeof zodSchema>;
function assertType<T>(_value: T) {}
assertType<Person>({} as InferredPerson); |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
Perhaps this thread might be of some help: #1928 |
Beta Was this translation helpful? Give feedback.
-
In my situation, I have an application where types are automatically exported from the backend, but do not contain validation logic. So I write the zod schema in the frontend, but I do want it to adhere to the exported types. While this is not possible yet with zod, I made this simple wrapper function as a workaround that makes sure a zod object adheres to a type, for anybody else stumbling upon this: export function validate<
NativeType,
SchemaType extends ZodType<NativeType> = ZodType<NativeType>
>(schema: SchemaType) {
return schema;
} You would use it like this: // exported from backend
type UpdateUserRequestData = {
username: string;
age: number;
};
const updateUserSchema = validate<UpdateUserRequestData>(
z.object({
username: z.string().min(8).max(32),
age: z.number(),
})
);
validate<UpdateUserRequestData>(
z.object({
// typo in field name, should error
userName: z.string().min(8).max(32),
// zod type doesn't match up with TS type, should error
age: z.string(),
})
);
validate<UpdateUserRequestData>(
z.object({
// forgot to add a field that's required in TS type, should error
})
); This is just a workaround until we have a first-party feature built into zod, but it helped me bridge the time until then 🙂 |
Beta Was this translation helpful? Give feedback.
I reopened it here: #2807