我知道 zod 的目的是解析不受信任的输入数据并断言它的类型与您的架构匹配。
但通常这些数据是通过 Web API 传入的,至少保证其顶级形状,例如string或object。
看来 zod 对 进行顶级类型检查是有意义的parse(),即使只是为了防止拼写错误等愚蠢错误。但看起来,事实并非如此。
作为一个简化的例子来说明
const schema = z.string().email();
schema.parse(1); // no type error here - why?
Run Code Online (Sandbox Code Playgroud)
看起来parse(1)应该有一个编译时类型错误,因为我们知道文字number1 不可能在运行时正确验证。我们无法通过一些随机string输入来做到这一点 - 需要运行时解析以确保它是有效的电子邮件 - 但这里的数字似乎是明显的程序员错误,甚至不应该编译。
一个更实际的例子,这让我提出了这个问题
async function validateRequest(request: Request) {
const someSchema = z.object({ ... })
return someSchema.parse(request.json()) // didn't await request.json() so won't work
}
Run Code Online (Sandbox Code Playgroud)
像省略上述内容这样的愚蠢错误await,似乎应该很容易通过someSchema.parse()检查我是否将其传递给 anobject而不是 a 来发现Promise<object>。
那么,有没有办法用 zod 启用这种顶级类型检查呢?
或者这种行为是出于某种我不理解 zod 设计的原因而故意的吗?
我试图在 Zod 中寻找一种方法来做到这一点,但找不到任何令人信服的东西。我怀疑用例可能不受开箱即用的支持。如果您想继续使用 Zod 进行解析,一个建议是创建一个具有更严格类型的包装函数,在内部调用您的 Zod 架构。
// I went for a record type because Promise<any> is assignable to object
function parseResponse(input: Record<string, unknown>) {
const someSchema = z.object({ ... });
return someSchema.parse(input)
}
async function validateRequest(request: Request) {
return parseResponse(request.json()) // This will throw because now it sees the promise
}
Run Code Online (Sandbox Code Playgroud)
事实上,你可以像这样编写这种类型的助手:
import { z } from "zod";
const schema = z.object({
field: z.string(),
})
function restrict<T, Output, Def extends z.ZodTypeDef, Input = Output>(schema: z.ZodType<Output, Def, Input>) {
return (t: T) => schema.parse(t);
}
type InferTypes<Z> = Z extends z.ZodType<infer Output, infer Defs, infer Input> ? [Output, Defs, Input] : [never, never, never];
type InferOutput<Z> = InferTypes<Z>[0];
type InferDefs<Z> = InferTypes<Z>[1];
type InferInput<Z> = InferTypes<Z>[2];
const validate = restrict<
Record<string, unknown>,
InferOutput<typeof schema>,
InferDefs<typeof schema>,
InferInput<typeof schema>
>(schema);
validate({}); // This typechecks because it's possible
async function foo(req: Request) {
return validate(req.json()); // This has a type error.
}
Run Code Online (Sandbox Code Playgroud)
唯一真正的缺点是您需要进行类型推断才能使泛型正常工作。
如果您对替代库持开放态度,这在io-ts中以相对一流的方式得到支持。您可以明确声明模式的输入和输出类型,它们默认开始unknown。权衡是开发人员经验。io-ts使用需要大量时间来学习的函数范式。
| 归档时间: |
|
| 查看次数: |
3152 次 |
| 最近记录: |