Closed stackoverfloweth closed 3 weeks ago
I'm not sure if I understand you correctly, but if you mean something like a checkbox that returns "true" or "" (aka false), then the solution would be something like this.
import * as v from 'valibot';
v.object({
foo: v.optional(v.pipe(v.string(), v.transform((val) => {
return val == "true";
})))
})
The schema indicates that the field is generally optional, but if filled, it can ultimately represent a Boolean with the value true|false.
and if you want only booleans as result you can define the defaultValue of Optional as "false" like
import * as v from 'valibot';
v.object({
foo: v.optional(v.pipe(v.string(), v.transform((val) => {
return val == "true";
})), "false")
})
And if you really want a undefined | string
v.object({
foo: v.optional(v.pipe(v.string(), v.transform((val) => {
return val.trim() === "" ? undefined : val;
})))
})
thanks for the input @JacKyDev. Let me provide a more nuanced example
const stringToNumberSchema = v.pipe(
v.string(),
v.decimal(),
v.transform(Number),
);
const test = v.optional(
v.pipe(stringToNumberSchema, v.minValue(0), v.maxValue(100)),
);
In this situation, when the value ""
is sent to test
I get the error
Invalid decimal: Received \"\",
In an attempt to apply your suggestion above I ended up with this
const stringToNumberSchema = v.pipe(
v.string(),
v.transform((value) => (value.trim() === '' ? undefined : value)),
v.decimal(),
v.transform(Number),
);
const test = v.optional(
v.pipe(stringToNumberSchema, v.minValue(0), v.maxValue(100)),
);
however, this has a TS error on v.decimal()
Type 'undefined' is not assignable to type 'string'
and at runtime still produces an error
Invalid decimal: Received undefined
I would rather have the question of what speaks against using 0 as the value when the input is an empty string
?
The code would be as follows:
import * as v from 'valibot';
const stringToNumberSchema = v.pipe(
v.string(),
v.transform((value: string) => (value.trim() === '' ? 0 : Number(value))),
);
const test = v.optional(
v.pipe(stringToNumberSchema, v.minValue(0), v.maxValue(100)),
);
const result = v.safeParse(test, '');
console.log(result);
The following aspects would result:
empty string
, then Success => Output 00
- 100
, then Success => Output 0 - 100< 0 || > 100
, error because the value is invalidundefined
, successful with undefined.If 0
as a value makes sense, you could also extend the optional with the following line:
...
const test = v.optional(
v.pipe(stringToNumberSchema, v.minValue(0), v.maxValue(100)),
"0"
);
...
This would result in an output of 0
even when the value is undefined
, and the schema would always be of type number
in a successful case.
Furthermore, I don't understand the check for decimal
because the schema only requires that the value is a number. In that case the problem is that empty string
is not a valid decimal string and failed.
I hope this helps; otherwise, feel free to provide a bit more context so I can better understand.
Here is another option. Try it out in our playground.
import * as v from 'valibot';
const Schema = v.optional(
v.union([
v.pipe(
v.literal(''),
v.transform(() => undefined),
),
v.pipe(
v.string(),
v.decimal(),
v.transform(Number),
v.minValue(0),
v.maxValue(100),
),
]),
);
when I have schemas with
as the user backspaces to an empty input the control will usually emit a value of
""
.I played around with using
v.fallback
to circumvent any validation errors but what I was hoping for is a rule that will actually translate an empty string to undefined.