Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to discard paricular field in .refine() or somewhere else without changing the schema? #2525

Closed
xsjcTony opened this issue Jun 21, 2023 · 1 comment

Comments

@xsjcTony
Copy link

xsjcTony commented Jun 21, 2023

Re-use the example in #2524:
https://stackblitz.com/edit/vitejs-vite-c6cz55?file=src%2FApp.tsx

In the example above, I first entered something in passport, then switched to driver_license, but when I submit the form, the value of passport is there as well.

I know this is expected since I defined it in the schema, just want to know whether there's a way to get around?

The discarding totally satisfies the schema, since both passport and driver_license is optional, hence discarding them won't break the type.

I'm aware that I can use z.discriminatedUnion() for this particular case, but it's not really my preferred solution, as in the real-world case, the complexity of the form is ridiculous, where usage of Discriminated Union will only make the schema even harder to organize in my opinion.

And I want the interface to looks like a simple single one instead of complex intersection with discriminated union

// This is what I need
interface User {
  name: string;
  age: number;
  id_type: 'passport' | 'driver_license'
  driver_license?: string;
  passport?: string;
}
// Instead of
type User = {
  name: string;
  age: number;
} & ({
  id_type: 'passport';
  passport: string;
} | {
  id_type: 'driver_license'
  driver_license: string;
})
// Or
type User = {
  id_type: 'passport';
  name: string;
  age: number;
  passport: string;
} | {
  id_type: 'driver_license';
  name: string;
  age: number;
  driver_license: string;
}

image

In yup, I can still do transform after when condition (e.g. transform to undefined), can I do something similar like conditionally discard a field in .refine() or .superRefine() in zod? I currently can't find a way to do so.


Or, as another solution, is it possible to make a new feature that removes all falsy value or any specified value during parse? e.g. Automatically remove empty string ''

@stale stale bot added the stale No activity in last 60 days label Sep 20, 2023
@JacobWeisenburger
Copy link
Contributor

Is this what you are looking for?

import _ from 'lodash'

const baseUserSchema = z.object( {
    name: z.string().min( 1 ),
    age: z.string().pipe( z.coerce.number().min( 18 ) ),
    id_type: z.enum( [ 'passport', 'driver_license' ] ),
    passport: z.string().optional(),
    driver_license: z.string().optional(),
} )

const requiredFields: ( keyof typeof baseUserSchema.shape )[] = [
    'name',
    'age',
    'id_type',
]

const userSchema = baseUserSchema.transform( x => _.pick( x, [ ...requiredFields, x.id_type ] ) )
type User = z.infer<typeof userSchema>
// type User = {
//     name: string;
//     age: number;
//     id_type: "passport" | "driver_license";
//     passport?: string | undefined;
//     driver_license?: string | undefined;
// }

console.log(
    userSchema.parse( {
        age: '50',
        driver_license: '456',
        id_type: 'driver_license',
        name: 'abc',
        passport: '123',
    } )
)
// {
//     name: "abc",
//     age: 50,
//     id_type: "driver_license",
//     driver_license: "456"
// }

console.log(
    userSchema.parse( {
        age: '50',
        driver_license: '456',
        id_type: 'passport',
        name: 'abc',
        passport: '123',
    } )
)
// {
//     name: "abc",
//     age: 50,
//     id_type: "passport",
//     passport: "123"
// }

If you found my answer satisfactory, please consider supporting me. Even a small amount is greatly appreciated. Thanks friend! 🙏
https://github.com/sponsors/JacobWeisenburger

@stale stale bot removed the stale No activity in last 60 days label Sep 26, 2023
Repository owner deleted a comment from stale bot Sep 26, 2023
Repository owner locked and limited conversation to collaborators Sep 26, 2023
@JacobWeisenburger JacobWeisenburger converted this issue into discussion #2811 Sep 26, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants