Replies: 17 comments 12 replies
-
Would be very useful! |
Beta Was this translation helpful? Give feedback.
-
Having a z.array(z.string()).refine(items => new Set(items).size === items.length, {
message: 'Must be an array of unique strings',
}) |
Beta Was this translation helpful? Give feedback.
-
I agree @joaoGabriel55, it would be very useful! |
Beta Was this translation helpful? Give feedback.
-
Has there been any update on this? Would be super useful to validate a unique array of primary keys without hitting the db layer. |
Beta Was this translation helpful? Give feedback.
-
I'm working on a solution for that. |
Beta Was this translation helpful? Give feedback.
-
No I meant that if the duplicate items array has many dense objects, logging them would be expensive.
On Sep 14, 2023, at 2:22 AM, ValTashkov ***@***.***> wrote:
I don't see where we would need JSON.stringify in this example, even with nested objects
We add second argument to the method, that is a callback that takes as first argument an array of the duplicated items. After that you can do whatever you like. In my case I am mapping the array of user to just the names
—
Reply to this email directly, view it on GitHub<#2316 (reply in thread)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AKO6F3JCQXNYPDLWTJD6ZN3X2KPDPANCNFSM6AAAAAAWZBHTTA>.
You are receiving this because you commented.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Made a simple helper: import z from 'zod';
function zUniqueArray<
ArrSchema extends z.ZodArray<z.ZodTypeAny, 'many'>,
UniqueVal
>(
uniqueBy: (item: z.infer<ArrSchema>[number]) => UniqueVal,
schema: ArrSchema
) {
return schema.superRefine((items, ctx) => {
const seen = new Set<UniqueVal>();
for (const [i, item] of items.entries()) {
const val = uniqueBy(item);
if (seen.has(val)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Unique property validation failed`,
path: [i],
});
} else {
seen.add(val);
}
}
});
}
const uniqueIdSchema = zUniqueArray(
(obj) => obj.id,
z.array(z.object({ id: z.number() }))
);
// succeeds
console.log(uniqueIdSchema.safeParse([{ id: 1 }, { id: 2 }]));
// fails
console.log(uniqueIdSchema.safeParse([{ id: 1 }, { id: 1 }])); |
Beta Was this translation helpful? Give feedback.
-
I didn't read the discussion much. I am using this z.array().transform((data) => uniq(data)) |
Beta Was this translation helpful? Give feedback.
-
Another way is to use superRefine as per the docs: https://zod.dev/?id=superrefine const Strings = z.array(z.string()).superRefine((val, ctx) => {
if (val.length !== new Set(val).size) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `No duplicates allowed.`,
});
}
}); |
Beta Was this translation helpful? Give feedback.
-
This works. How would you then validate each item of the array, to e.g. display an error message at that input field that had caused the "duplication"? |
Beta Was this translation helpful? Give feedback.
-
I had to change this part from |
Beta Was this translation helpful? Give feedback.
-
You can combine const itemSchema = z.object({
prop: z.string()
})
items: z
.array(itemSchema)
.refine(items => _.isEqual(items, _.uniqBy(items, 'prop'))) |
Beta Was this translation helpful? Give feedback.
-
A more generalized version (based on the past answer of @HassanZahirnia). function uniqueArray(schema: ZodType) {
return z
.array(schema)
.refine((items) => new Set(items).size === items.length, {
message: 'All items must be unique, no duplicate values allowed',
});
}
const schema = {
setString: uniqueArray(z.string().minLength(87)),
setNumber: uniqueArray(z.number()),
setBoolean: uniqueArray(z.boolean()),
} |
Beta Was this translation helpful? Give feedback.
-
I just found out that zod has Sets, which might be more what someone would like to use instead of array with uniquness. |
Beta Was this translation helpful? Give feedback.
-
Zod sets is amazing for simple native types But what if we want to customize what "unique" means? Suppose I have an array of objects with an id field and I want to make sure that the ids do not repeat in the array, then zod Sets does not fulfill the criteria, unless I missed some part of the documentation |
Beta Was this translation helpful? Give feedback.
-
Another problem with export function zodUniqueArray<Schema extends ZodSchema, K>(
schema: Schema,
idSelector: (item: Schema['_output']) => K = item => item
) {
return z.array(schema)
.refine(
items => {
const ids = new Set<K>(items.map(i => idSelector(i)));
return ids.size === items.length;
},
'array-items-must-be-unique'
);
} Usage without a id selectorsuppose I have nested records and I need the leaf string arrays to have unique values const domainSoftwareMap: Record<string, Record<string, string[]>> = {}; Usage with an id selectorSuppose I have a list of objects, and I need to check uniqueness by the const roles: { _id: string, name: string, descripton: string }[]= []; |
Beta Was this translation helpful? Give feedback.
-
Validating that an array has no duplicates and transforming into a const set = <A extends ZodTypeAny, B extends z.ArrayCardinality>(array: z.ZodArray<A, B>) =>
array.transform((items, context) => {
const set = new Set(items)
if (set.size !== items.length) {
context.addIssue({
code: z.ZodIssueCode.custom,
message: "uniqueItems",
})
return z.NEVER
}
return set
}) |
Beta Was this translation helpful? Give feedback.
-
I was checking the docs to see if there was any way to validate if there was any duplicate items on an array, perhaps we could implement a
unique()
function that does just that for arrays?Or for more complex arrays:
Is this doable or is it out of scope?
Beta Was this translation helpful? Give feedback.
All reactions