Skip to content
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 create a generic zod parser factory that gives a picked schema with types? #2887

Open
zakia98 opened this issue Oct 20, 2023 · 2 comments

Comments

@zakia98
Copy link

zakia98 commented Oct 20, 2023

Hi all,

I'm trying to create a generic zod parser factory that takes a schema and a list of fields that transforms that schema into a picked schema, but I am having an issue where the return type information is filtered out to any.

Here's what I have so far:

    const parseFactory = (schema: z.AnyZodObject) =>  { 
        return <T extends keyof z.infer<typeof schema>>({item, fields}: {item: unknown, fields: T[]}): Pick<z.infer<typeof schema>, T> | undefined=> {
          try {
            const pickedSchema = schema.pick(Object.fromEntries(fields.map(field => [field, true])))
            return pickedSchema.parse(item)
          } catch (error) {
            // error handling
          }
        }
    }

However, in the above, the type of the return is :

    {
        [x: string]: any;
        [x: number]: any;
    }

Any help would be appreciated!

@zakia98
Copy link
Author

zakia98 commented Nov 16, 2023

Sorry, just wondering if I could bump this?

@snigdha920
Copy link

I think the [x: string]: any; type is coming from the Object.fromEntries method, which does not type the keys of the object: https://github.com/microsoft/TypeScript/blob/8da951cbb629b648753454872df4e1754982aef1/src/lib/es2019.object.d.ts#L8

Related issue: microsoft/TypeScript#35745

Here's what works for me:

export type UserSchemaType = z.infer<typeof UserSchema>;

export function validateUserSchemaFields(
  fields: (keyof UserSchemaType)[],
  data: Partial<UserSchemaType>
) {
  try {
    UserSchema.pick(getMask(fields)).parse(data);
    return true;
  } catch {
    return false;
  }
}

function getMask<Schema extends z.AnyZodObject, Fields extends keyof z.TypeOf<Schema>>(arr: Fields[]) {
  return arr.reduce(
    (acc, item) => {
      acc[item] = true;
      return acc;
    },
    {} as { [k in Fields]?: true }
  );
}

This is not a factory because you can't pass the schema as a parameter, but once you have the schema this works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants