如何在TypeScript中使用Zod验证测试null值且避免类型错误?
问题:Zod验证中测试Null值时的TypeScript错误
背景代码
后端接口的Zod验证配置:
app.post( '/api/users', validateRequest({ body: z.object({ username: z.string(), email: z.string(), password: z.string(), }) }), async (req, res) => { const hashedPassword = await argon2.hash(req.body.password); await User.create({ ...req.body, password: hashedPassword, }); res.status(201).send({ message: 'User created' }); }, );
测试代码与报错
尝试测试username为null的场景:
it('should return a 400 status code when username is null', async () => { const response = await request(app) .post('/api/users') .send({ username: null, email: 'user@admin.com', password: 'pass4User', }); expect(response.statusCode).toBe(400); });
触发TypeScript错误:
Type 'null' is not assignable to type 'string'
解决方案
1. 用类型断言绕过TS检查
直接给发送的对象断言为any,让TS跳过类型校验:
it('should return a 400 status code when username is null', async () => { const response = await request(app) .post('/api/users') .send({ username: null, email: 'user@admin.com', password: 'pass4User', } as any); expect(response.statusCode).toBe(400); });
2. 定义测试专用的无效类型
如果需要多次测试不同无效值,可以定义一个兼容无效情况的类型:
type InvalidUserInput = Partial<Record<keyof {username: string; email: string; password: string}, string | null | undefined>>; it('should return a 400 status code when username is null', async () => { const invalidInput: InvalidUserInput = { username: null, email: 'user@admin.com', password: 'pass4User', }; const response = await request(app) .post('/api/users') .send(invalidInput); expect(response.statusCode).toBe(400); });
3. 基于Zod类型扩展测试用类型
利用Zod的z.infer获取原本的输入类型,再扩展允许字段为null/undefined:
import { z } from 'zod'; const UserSchema = z.object({ username: z.string(), email: z.string(), password: z.string(), }); type ValidUserInput = z.infer<typeof UserSchema>; type TestUserInput = Partial<Record<keyof ValidUserInput, ValidUserInput[keyof ValidUserInput] | null | undefined>>; it('should return a 400 status code when username is null', async () => { const testInput: TestUserInput = { username: null, email: 'user@admin.com', password: 'pass4User', }; const response = await request(app) .post('/api/users') .send(testInput); expect(response.statusCode).toBe(400); });
4. 用unknown类型中转
把测试输入声明为unknown再转换,避免TS校验:
it('should return a 400 status code when username is null', async () => { const testInput: unknown = { username: null, email: 'user@admin.com', password: 'pass4User', }; const response = await request(app) .post('/api/users') .send(testInput as any); expect(response.statusCode).toBe(400); });
这些方法的核心都是在测试场景下,绕过TS对有效输入的类型限制——毕竟我们要测试的就是无效输入的处理逻辑。
内容的提问来源于stack exchange,提问作者Stanley Ulili
相关产品推荐
相关产品推荐

