检查Zod类型是否等同于TypeScript接口?



我一直认为API调用的结果在TypeScript中是这样的:

interface Res {
films: string;
people: string;
}
const res: Res = await fetch("https://swapi.dev/api/")
.then((res) => {
return res.json();
})
.then(({ films, people }) => {
return {
films,
people,
};
});

后来我添加了运行时类型检查与Zod

const resSchema = z.object({
films: z.string(),
people: z.string(),
});
resSchema.parse(res);

这可以工作,但这意味着我有两个不同的类型定义要维护。在TypeScript中是否有一种方法可以检查resSchema的类型是否等于Res?

我知道zod可以推断:

type ResType = z.infer<typeof resSchema>
const res: ResType = await fetch("https://swapi.dev/api/")
.then((res) => {
return res.json();
})
.then(({ films, people }) => {
return {
films,
people,
};
});

然而,我不想使用这个,因为我不能一眼就看到ResType上的字段与Res相比,这是非常清楚的。

可以通过断言模式的类型而不是从模式推断类型来实现这一点。在您的示例中,如果您已经有了Res接口,您可以将schema定义为:

import { z } from "zod";
interface Res {
films: string;
people: string;
}
const schema: z.ZodType<Res> = z.object({
films: z.string(),
people: z.string(),
});

如果你更新Res,你会在你定义schema的那一行得到一个类型错误,即z.object的值不能再分配给你指定的ZodType

这也有一个很好的属性,即schema.parse的返回值也将在编辑器中显示为Res。如果您给接口一个有意义的名称和javadoc风格的注释,它们将被授予编辑器语言服务器中parse的返回值。

打印稿操场

虽然@Souperman的答案有效,但它不考虑null,undefined或可选属性(?)。

所以我开始寻找一个解决方案,可以…

解决方案1:

这将说明null,undefined或可选属性(?)。

它使用"tozod"包中。查看这里的github和npm。

你可以这样使用:

import { z } from "zod";
import { toZod } from "tozod";
interface Res {
films?: string; // Note that "films" is now optional
people: string;
}
const schema: toZod<Res> = z.object({
films: z.string().optional(), // removing .optional() will throw an error
people: z.string(),
});

我喜欢这个解决方案,但是我最近发现它不能很好地处理联合。

这是当我发现解决方案2…

解决方案2:

这是一个备选选项,但就像@Souperman的答案一样,它不考虑null,undefined或可选属性(?)。

我在这个问题线程中找到了这个解决方案。需要TS 4.9+。

使用新的TSsatisfies关键字和z.ZodType,我们可以检查Zod Type是否匹配TypeScript接口。如果不匹配,将抛出错误。

例如:

type User = {
id: number
name: string
age: number
}
const UserSchema = z.object({
id: z.number(),
name: z.string(),
age: z.number()
}) satisfies z.ZodType<User>

这是一个很酷的解决方案,但它不适合我,因为它不考虑null,undefined和可选属性。

解决方案3:

我目前正在寻找superstructjs而不是zod,因为有人在zod线程建议它。稍后再发回详细报道!

最新更新