zod icon indicating copy to clipboard operation
zod copied to clipboard

Allow array to return only valid items and not fail whole array

Open bmeverett opened this issue 2 years ago • 1 comments

When validating an array, I would like to only return the valid items in an array and not fail if one item fails.

This is a very basic example

const schema = z.object({
  arr: z.array(z.number())
})

const result = schema.safeParse({arr: [1,2,"3"]})

I would like this to return only the valid items

arr: [1,2]

I tried using refine on the array, but it seems to only be called when the array validates correctly. Is there a way to do this, or is this something you'd be willing to support?

bmeverett avatar Nov 07 '22 14:11 bmeverett

Hi @bmeverett,

I don't know if Zod maintainers will support this specific claim in the lib, but you can build a custom validator that uses error.issues to filter it manually based on invalid properties/items issued by zod.

I've implemented something like that just as a proof of concept:

const validator = (schema: z.Schema<any, any>) => (data: object) => {
  const response = schema.safeParse(data);

  if (response.success === false) {
    const errorPaths = response.error.issues.map((issue) => issue.path);

    let filteredData = data;
    errorPaths.forEach(
      (error) => (filteredData = filterByPath(filteredData, error))
    );

    return filteredData;
  }

  return data;
};

const result = validator(schema)(input);

The most difficult part is the filterByPath() function, which I've got something that works but maybe it's not perfect in performance terms and maybe does not cover all cases.

I would suggest you develop your own for your needs. For reference, you can see my implementation here in StackBlitz.

lucassarcanjo avatar Nov 18 '22 22:11 lucassarcanjo

@bmeverett Is this what you're looking for?

const schema = z.object( {
    arr: z.any().array().transform(
        arr => arr.map( item =>
            z.number().safeParse( item ).success ? item : undefined
        ).filter( Boolean )
    ),
} )

console.log( schema.parse( { arr: [ 1, 2, '3' ] } ) ) // { arr: [ 1, 2 ] }

JacobWeisenburger avatar Jan 03 '23 19:01 JacobWeisenburger

Thanks @JacobWeisenburger and @lucassarcanjo I think I can work with these.

bmeverett avatar Jan 04 '23 19:01 bmeverett