-
-
Notifications
You must be signed in to change notification settings - Fork 166
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
Method of modifying input type to account for acceptable invalid inputs #433
Comments
Thank you for creating this issue! This issue is related to discussion #376. Do you have an alternative name idea for |
|
I tried to implement |
Ahh, yes, I see the issue. I'm not a type expert by any measure, but I think this has to do with the lack of "partial type argument inference. " Either we infer all type arguments, or we infer none. The only path I can see, other than individually custom functions, is to use a curried function. For example: import type { BaseSchema, Input, Output } from "valibot";
/**
* Input schema type.
*/
export type InputSchema<
TInput,
TWrapped extends BaseSchema,
TOutput = Output<TWrapped>,
> = BaseSchema<Input<TWrapped> | TInput, TOutput> & {
/**
* The schema type.
*/
type: "input";
/**
* The wrapped schema.
*/
wrapped: TWrapped;
};
/**
* Creates a curried type-variant input schema function.
*
* @template TInput The type to be appended to the input type of the wrapped schema.
*
* @returns A curried function that creates a custom type-variant input schema.
*/
export const createInput = <TInput>() => {
return <TWrapped extends BaseSchema>(
wrapped: TWrapped,
): InputSchema<TInput, TWrapped> => {
return {
type: "input",
expects: wrapped.expects,
async: false,
wrapped,
_parse(input: unknown, config) {
return this.wrapped._parse(input, config);
},
};
};
}; This can be applied either like this... const nullableInput = createInput<null>();
const RepeatSchema = nullableInput(v.picklist(['daily', 'weekly', 'monthly']));
type RepeatInput = v.Input<typeof RepeatSchema>; // "daily" | "weekly" | "monthly" | null
type RepeatOutput = v.Output<typeof RepeatSchema>; // "daily" | "weekly" | "monthly" Or like this... const RepeatSchema = createInput<null>()(v.picklist(['daily', 'weekly', 'monthly']));
type RepeatInput = v.Input<typeof RepeatSchema>; // "daily" | "weekly" | "monthly" | null
type RepeatOutput = v.Output<typeof RepeatSchema>; // "daily" | "weekly" | "monthly" Certainly sub-optimal. I'll completely understand if this isn't something you want to add to Valibot, but I'm very glad to have a solution! |
Yes, that is correct. Thanks for the research! For now, I prefer to wait for feedback from other developers on this issue. |
I think that this is now possible using our new import * as v from 'valibot';
const Schema1 = v.picklist(['foo', 'bar']);
const Schema2 = v.pipe(v.nullable(Schema1), Schema1);
type Input = v.InferInput<typeof Schema2>; // 'foo' | 'bar' | null
type Output = v.InferOutput<typeof Schema2>; // 'foo' | 'bar' |
This is a feature request to provide a method of modifying the input type of a schema to account for acceptable invalid inputs.
The use case I am aware of is when composing forms using controlled inputs such as React + MUI or MUI Joy where specific values like
null
andliteral('')
(among others) have special meaning as empty value. Having that enshrined in the shape of the form state is helpful to ensure that the state is initialized correctly and allows the developer to handle those cases directly when orchestrating form logic.In some ways, this is a usage-specific edge case. However, this case is very common, and the solution appears inexpensive.
One drawback is adding an otherwise useless pass-through function that will be compiled when used. In my opinion, the benefits for DX and quality outcomes outweigh the drawbacks.
The following is an API proposed by Fabian in a discussion. (Please note that this is an ultra-simplified example to make it easy to reason about. Objects and deeply nested structures cannot have simple type adjustments made to individual properties without a mechanism like this)
Alternatives include
value
andonChange
manipulation to modify values back to undefined, but that does require a lot more effort, which, in my opinion, attempts to hide the reality of those components behind an error-prone layer of transformations and makes it difficult or impossible for those using rigorous linter configurations.The
input
method provides a clean and easy-to-use API that surfaces acceptable invalid inputs, making them plain to see during development and easy to address, and assists in avoiding additional unnecessary effort.The text was updated successfully, but these errors were encountered: