Search code examples
typescriptzod

Make Zod parse if available, and if not skip element


I've searched through the documentation but find no solution for this case. I've got the following schemas.

const RelationSchema = z.object({
    guid: z.string(),
    createdDate: z.preprocess(castToDate, z.date()),
    modifiedDate: z.preprocess(castToDate, z.date()).nullable(),
    name: z.string(),
    publicationtype: z.string(),
    contentType: z.string(),
});
export const NobbRelationsSchema = z.array(NobbRelationSchema);

When parsing an array with NobbRelationsSchema.parse() I sometimes get back name as undefined. In these cases I would like Zod not to throw an error, but instead just remove that element and continue with the rest. A kind of filtering.

The option I see is to use safeParse and set name as optional and filter out these afterwards. However, it messes up the TypeScript type checking later in code, as name should always be set for valid elements.


Solution

  • The option I see is to use safeParse and set name as optional and filter out these afterwards.

    I think the simplest thing to do would be to add something special rather than using z.array: safe parse an unknown array and filter that. For example:

    import { z } from 'zod';
    // -- snip your code here --
    type NobbRelation = z.TypeOf<typeof RelationSchema>;
    
    function parseData(data: unknown) {
      // First parse the shape of the array separately from the elements.
      const dataArr = z.array(z.unknown()).parse(data);
    
      // Next parse each element individually and return a sentinal value
      // to filter out. In this case I used `null`.
      return dataArr
        .map(datum => {
          const parsed = RelationSchema.safeParse(datum);
          return parsed.success ? parsed.data : null;
        })
        // If the filter predicate is a type guard, the types will be correct
        .filter((x: NobbRelation | null): x is NobbRelation => x !== null);
    }
    

    For the most part this shouldn't limit your options. If you have other limitations you want to impose on the array, like a maximum length, you can do that when you process the unknown array.

    If you have additional post processing you would like to do with transform, you could do that with a step after the filter.

    If you want to have the type for NobbRelationsSchema you could derive that as:

    type NobbRelations = NobbRelation[]; // Or just write this inline