TypeScript判别联合类型结合Zod解析报错求助
TypeScript判别联合类型与Zod safeParse返回值类型问题
我尝试用TypeScript实现判别联合类型,在条件分支处理时遇到问题。当前代码如下:
import { z, ZodError } from 'zod'; let parsedUser = z.object({ password: z.string().min(1).max(8), firstName: z.string().min(1).max(8), lastName: z.string().min(1).max(8) }); type User = { password: string, firstName: string, lastName: string } type UserParserOutcome = ZodError | User; export const userParser = (user: unknown): UserParserOutcome => { let result = parsedUser.safeParse(user); if (!result.success) return result.error; else return result.data as User; };
问题:我定义了UserParserOutcome作为ZodError或User的联合类型,按Zod文档,safeParse应返回error或data属性。else分支正常,但WebStorm标记return result.error行报错,请问遗漏了什么?
问题原因
Zod的safeParse返回的error并非通用的ZodError类型,而是带泛型参数的ZodError<z.infer<typeof parsedUser>>——也就是和当前schema绑定的具体错误类型。TypeScript会严格区分泛型类型和基础类型,所以直接返回result.error时,类型无法匹配你手动定义的UserParserOutcome中的ZodError。
另外,你手动定义的User类型其实和parsedUser schema的类型重复了,完全可以用Zod的类型推导来避免重复维护。
解决方案
有两种可行的修改方式:
方案1:让TypeScript自动推导返回类型
去掉手动定义的UserParserOutcome,直接让TS根据safeParse的结果自动推导函数返回类型,同时用z.infer推导User类型:
import { z, ZodError } from 'zod'; const parsedUser = z.object({ password: z.string().min(1).max(8), firstName: z.string().min(1).max(8), lastName: z.string().min(1).max(8) }); // 自动推导User类型 type User = z.infer<typeof parsedUser>; // 去掉手动定义的返回类型,让TS自动推导 export const userParser = (user: unknown) => { const result = parsedUser.safeParse(user); if (!result.success) return result.error; return result.data; };
方案2:修正手动定义的联合类型
如果一定要保留UserParserOutcome,需要将其中的ZodError替换为和schema绑定的具体错误类型,同时用z.infer推导User:
import { z, ZodError } from 'zod'; const parsedUser = z.object({ password: z.string().min(1).max(8), firstName: z.string().min(1).max(8), lastName: z.string().min(1).max(8) }); type User = z.infer<typeof parsedUser>; // 绑定schema的具体ZodError类型 type UserParserOutcome = ZodError<User> | User; export const userParser = (user: unknown): UserParserOutcome => { const result = parsedUser.safeParse(user); if (!result.success) return result.error; return result.data; };
额外说明
- 把
let parsedUser改成const parsedUser,这样TypeScript能更精准地推导schema的类型。 - 不需要用
as User断言result.data,因为safeParse成功时data的类型已经是User了,断言完全多余。
内容的提问来源于stack exchange,提问作者user1790300
相关产品推荐
相关产品推荐

