假设我有两种类型,
BasicUser
和AdminUser
,它们合并为一种类型User
。
interface UserBase {
name: string
authenticationType: AuthenticationType;
}
interface BasicUser extends UserBase {
authenticationType: 'basicUser';
privileges: string;
}
interface AdminUser extends UserBase {
authenticationType: 'adminUser';
}
export type User = BasicUser | AdminUser;
我正在尝试构建一个模式,可以验证
User
类型,无论它是构造为 AdminUser
还是 BasicUser
。
import * as yup from 'yup';
import { AuthenticationType, User } from './types';
const bobAdmin: User = {
name: 'Bob',
authenticationType: 'adminUser',
}
const sallyBasicUser: User = {
name: 'Sally',
authenticationType: 'basicUser',
privileges: 'read'
}
// Schema validation fails typecheck
const userSchema: yup.ObjectSchema<User> = yup.object({
name: yup.string().required(),
authenticationType: yup.string().oneOf<AuthenticationType>(['basicUser', 'adminUser']).defined().required(),
privileges: yup.string().when('authenticationType', ([authenticationType], schema) => {
if(authenticationType === 'basicUser') {
return schema.required();
}
return schema;
})
});
验证确实有效,但 TypeScript 抱怨架构不满足
User
类型。
我尝试将模式分解为两个不同的模式并使用
mixed().oneOf([])
,但这也不起作用。
有没有人可以提供任何解决方法或提示?谢谢你。
https://stackblitz.com/edit/vitejs-vite-fszugq?file=src%2Fmain.ts
显然,是的,不支持该功能。我的解决方法是将架构的失败部分转换为
any
...不理想。
Zod 使用 歧视性工会 很好地处理了这个案例。
const userSchema = z.discriminatedUnion('authenticationType', [
z.object({ authenticationType: z.literal('adminUser') }).merge(baseUserSchema),
z.object({ authenticationType: z.literal('basicUser'), privileges: z.string() }).merge(baseUserSchema),
]) satisfies z.ZodType<User>; // Gives you schema typing against User type
https://stackblitz.com/edit/vitejs-vite-bcbhz1?file=src%2Fmain.ts