⚓
zodでtransformした後,ジェネリクスで型エラーが出る問題の解決法
zodにはtransform機能がある
zodでは,スキーマにtransform()メソッドを使用することで,パースを行った後に別の型に変換することができます。
しかし,ジェネリクスと組み合わせるときには注意が必要です。
結論だけ書くと,スキーマの型として以下のように指定すると良いです。
z.ZodType<I, z.ZodTypeDef, O>
エラーの例
import axios from "axios";
import { z } from "zod";
const outputSchema = z
.object({ name: z.string(), age: z.number() })
.transform((data) => ({
...data,
isAdult: data.age >= 18,
}));
export const hogeApi = async <O>({
endpoint,
outputSchema,
}: {
endpoint: string;
outputSchema: z.ZodType<O>;
}) => {
const response = await axios.get(endpoint);
const validatedData = outputSchema.parse(response.data);
return validatedData;
};
const res = await hogeApi({
endpoint: "https://example.com",
outputSchema,
});
// エラー発生
// プロパティ 'isAdult' は型 '{ name: string; age: number; }' に存在しません。ts(2339)
console.log(res.isAdult);
上記のように,transformによりisAdultプロパティが追加されているはずなのに,存在しないというエラーが出ます。
解決法
解決策としては単純です。
zodType<O>
を
zodType<O, z.ZodTypeDef, T>
に書き換えるだけです。
解決例
import axios from "axios";
import { z } from "zod";
const outputSchema = z
.object({ name: z.string(), age: z.number() })
.transform((data) => ({
...data,
isAdult: data.age >= 18,
}));
export const hogeApi = async <O, T>({
endpoint,
outputSchema,
}: {
endpoint: string;
outputSchema: zodType<O, z.ZodTypeDef, T>;
}) => {
const response = await axios.get(endpoint);
const validatedData = outputSchema.parse(response.data);
return validatedData;
};
const res = await hogeApi({
endpoint: "https://example.com",
outputSchema,
});
// エラーが出ない!!
console.log(res.isAdult);
解説
Zodの型システムについて
ZodのZodType
は3つの型パラメータを持っています:
ZodType<Input, Def, Output>
-
Input
: スキーマが受け入れる入力の型 -
Def
: Zodの内部で使用される型定義(通常はz.ZodTypeDef
を使用) -
Output
: スキーマが生成する出力の型(transform()
メソッドで変更された場合に重要)
なぜエラーが発生したのか
元のコードでz.ZodType<O>
と指定した場合、TypeScriptはInput
とOutput
が同じ型O
であると解釈します。つまり、transform()
メソッドによる型の変更が反映されていませんでした。
解決策の仕組み
z.ZodType<O, z.ZodTypeDef, T>
と指定することで:
-
O
は入力の型(変換前)を表します。 -
z.ZodTypeDef
はZodの内部型定義を指定します。 -
T
は出力の型(変換後)を表します。
この指定により、TypeScriptがtransform()
メソッドによる型の変更を正確に追跡できるようになります。
Discussion