💎

z.inferを使いたくない

に公開

z.inferを使いたくない

  • 型を制御できない
  • zodが生成した型を使いたくない
  • 自前の型でzodのスキーマを制御したい

z.inferを使う場合

import z from "zod";

const user = z.object({
	id: z.string(),
	email: z.string(),
	name: z.string(),
	age: z.number().optional(),
});
type User = z.infer<typeof user>;

z.inferを使わない場合

import z from "zod";

type User = {
	id: string;
	email: string;
	name: string;
	age?: number;
};
const user = z.object({
	id: z.string(),
	email: z.string(),
	name: z.string(),
	age: z.number(),
} satisfies { [K in keyof User]-?: z.ZodType<User[K]> });

再利用性を高めるために...

import z from "zod";

type User = {
	id: string;
	email: string;
	name: string;
	age?: number;
};

type SchemaFor<T> = { [K in keyof T]-?: z.ZodType<T[K]> };

const user = z.object({
	id: z.string(),
	email: z.string(),
	name: z.string(),
	age: z.number(),
} satisfies SchemaFor<User>);

SchemaForの役割

  • keyof TでTのキーを取得する
  • [K in keyof T]でTのキーをループする
  • -?でオプショナルを外す
  • z.ZodType<T[K]>でzodの型に変換する
  • { [K in keyof T]-?: z.ZodType<T[K]> }でTのキーをzodの型に変換したオブジェクト型を作成する
  • satisfiesで型チェックを行う

どう見える?

スキーマのプロパティが不足している時

コード
import z from "zod";

type User = {
	id: string;
	email: string;
	name: string;
	age?: number;
};

type SchemaFor<T> = { [K in keyof T]-?: z.ZodType<T[K]> };

const user = z.object({
	id: z.string(),
	email: z.string(),
	name: z.string(),
	// age: z.number().optional(),
} satisfies SchemaFor<User>);


User型にないプロパティがある時

コード
import z from "zod";

type User = {
	id: string;
	email: string;
	name: string;
	age?: number;
};

type SchemaFor<T> = { [K in keyof T]-?: z.ZodType<T[K]> };

const user = z.object({
	id: z.string(),
	email: z.string(),
	name: z.string(),
	age: z.number().optional(),
	additional: z.any(),
} satisfies SchemaFor<User>);


スキーマの型が違う時

コード
import z from "zod";

type User = {
	id: string;
	email: string;
	name: string;
	age?: number;
};

type SchemaFor<T> = { [K in keyof T]-?: z.ZodType<T[K]> };

const user = z.object({
	id: z.string(),
	email: z.string(),
	name: z.number(),
	age: z.number().optional(),
} satisfies SchemaFor<User>);


最後に

挙動はSchemaForを調整すれば変えられるので用途に合わせて作ればいい。

Discussion