-
-
Notifications
You must be signed in to change notification settings - Fork 195
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
TS error when using custom() #487
Comments
Don't throw inside of You can forward issues with this method: https://valibot.dev/api/forward/ |
Hum, I saw some issues where people were throwing inside Imagine this scenario, how can I achieve the same result without throwing in custom? codOutrasNacionalidades: v.array(v.string([v.minLength(1, 'required.otherNationalities')]), [
v.minLength(1, 'required.otherNationalities'),
v.custom((input) => {
const duplicates = input.filter((item, index) => input.indexOf(item) !== index);
const issues: v.SchemaIssues = [] as unknown as v.SchemaIssues;
if (duplicates.length > 0) {
input.forEach((val, index) => {
if (duplicates.includes(val)) {
issues.push(
createValibotIssue({
fieldPath: `pessoa.codOutrasNacionalidades.${index}`,
input: { 'pessoa.codOutrasNacionalidades': input },
message: 'validation.uniqueNationalities',
reason: 'array',
}),
);
}
});
}
if (issues.length > 0) {
throw new v.ValiError(issues);
}
return true;
}),
]), export const createValibotIssue = ({
message,
reason,
input,
fieldPath,
}: Pick<SchemaIssue, 'message' | 'reason'> & { input: Record<string, unknown>; fieldPath: string }): SchemaIssue => ({
context: '',
expected: null,
input: input[fieldPath],
message,
path: [
{
input,
key: fieldPath,
origin: 'value',
type: 'object',
value: input[fieldPath],
},
],
reason,
received: '',
}); |
I would return |
Also we have a |
I've seen the discussion, I'm waiting for that :).
I didn't try it yet, but do |
No, but that's an interesting idea!
With my current code pipeline actions accept a |
I think so, in my current implementation, this is important to select the duplicated option, and with the code that I've shared here, it works.
Those are great news, I'm looking forward to testing it. |
I plan to publish a blog post in two or three weeks about the results and investigations of the new |
Although it's not recommended, I'll let In summary, I would like to have:
const Schema = v.object(
{
mainNationality: v.string([v.minLength(1, 'required.nationality')]),
otherNationalities: v.array(v.string([v.minLength(1, 'required.otherNationalities')]), [
v.minLength(1, 'required.otherNationalities'),
(custom valiration to check duplicated)
])
(...other fields)
},
[
v.<someMethod>((inputs) => {
// If some element in otherNationalities is equal to the mainNationality,
// add an issue to the otherNationalities item index
}),
],
); |
Hi @fabian-hiller I saw your comment on the rewrite PR, I was thinking about testing the new implementation of |
It is possible, but you have to write your own action. The concept is very simple. Here is an example where I have called the action "items": import {
_addIssue,
type BaseIssue,
type BaseValidation,
type ErrorMessage,
} from 'valibot';
/**
* Items issue type.
*/
export interface ItemsIssue<TInput extends unknown[]>
extends BaseIssue<TInput> {
/**
* The issue kind.
*/
readonly kind: 'validation';
/**
* The issue type.
*/
readonly type: 'items';
/**
* The expected input.
*/
readonly expected: null;
/**
* The validation function.
*/
readonly requirement: (input: TInput[number]) => boolean;
}
/**
* Items action type.
*/
export interface ItemsAction<
TInput extends unknown[],
TMessage extends ErrorMessage<ItemsIssue<TInput>> | undefined,
> extends BaseValidation<TInput, TInput, ItemsIssue<TInput>> {
/**
* The action type.
*/
readonly type: 'items';
/**
* The action reference.
*/
readonly reference: typeof items;
/**
* The expected property.
*/
readonly expects: null;
/**
* The validation function.
*/
readonly requirement: (input: TInput[number]) => boolean;
/**
* The error message.
*/
readonly message: TMessage;
}
/**
* Creates an items validation action.
*
* @param requirement The validation function.
*
* @returns An items action.
*/
export function items<TInput extends unknown[]>(
requirement: (input: TInput[number]) => boolean
): ItemsAction<TInput, undefined>;
/**
* Creates an items validation action.
*
* @param requirement The validation function.
* @param message The error message.
*
* @returns An items action.
*/
export function items<
TInput extends unknown[],
const TMessage extends ErrorMessage<ItemsIssue<TInput>> | undefined,
>(
requirement: (input: TInput[number]) => boolean,
message: TMessage
): ItemsAction<TInput, TMessage>;
export function items(
requirement: (input: unknown) => boolean,
message?: ErrorMessage<ItemsIssue<unknown[]>>
): ItemsAction<unknown[], ErrorMessage<ItemsIssue<unknown[]>> | undefined> {
return {
kind: 'validation',
type: 'items',
reference: items,
async: false,
expects: null,
requirement,
message,
_run(dataset, config) {
if (dataset.typed) {
for (let index = 0; index < dataset.value.length; index++) {
const item = dataset.value[index];
if (!this.requirement(item)) {
_addIssue(this, 'item', dataset, config, {
input: item,
path: [
{
type: 'array',
origin: 'value',
input: dataset.value,
key: index,
value: item,
},
],
});
}
}
}
return dataset;
},
};
} Now you can write the following code: import * as v from 'valibot';
import { items } from './your-path';
const Schema = v.pipe(
v.array(v.string()),
items((item) => item.startsWith('foo'), 'Your message')
); |
Thanks. I'll try that, do you plan on implementing it in valibot? |
Yes, I will consider it. Do you have some good alternatives names for the action? |
The only one that I could think of is |
I was thinking, it would be nice if the callback had 2 or 3 arguments With that we could create validations based on other items, for example, identify duplicated values.
Let me know what you think. Another requirement I can think that would be great is an action to validate properties based on other properties. Let me give you an example: {
"primaryEmail": "[email protected]",
"otherEmails": ["[email protected]", "[email protected]"]
} To validate that the I hope I didn't confuse you. |
Thanks! Will think about it! Both names could work.
I agree!
This requires a custom validation in the pipeline of the object definition with a forward to the appropriate field. Note: We renamed |
Oh, that's what I need, I thought that the Please update this issue when this action gets done. |
@fabian-hiller I was playing around and found that the |
You are right. I will probably add it today or tomorrow. I will ping you then. |
I am working on it and will probably add it later today. |
Done |
Thanks, I'll play with it again. |
Is this issue resolved? I will close it for now, but will reopen it if not. |
Feel free to create a new issue (or PR) to add an |
I'll check it ASAP and let you know.
I'll open one issue latter today. |
I'm not able to put a schema to work with this requirement, can you help here?
The One possible solution that came to my mind is a method that allow us to add issues to the list of issues already created by valibot validations. Something like: v.someMethod((inputs, ctx) => {
// ...(my custom validation with ctx.addIssue())...
return ctx.issues // Or other type of return
}) |
Maybe we should add an advanced |
I agree, let's do the following, I'll close this issue and open a new one with a recap of this one. |
The property schema: 'object' gives me a TS error and I can't put it to work.
The text was updated successfully, but these errors were encountered: