Skip to content

fix: getFallbacks use fallback value of an object #1155

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

muningis
Copy link
Contributor

Resolves #1150

This is, semi breaking change though I would assume, as it changes default behaviour.
Previously, it would check for fallbacks of an object, and ignore if it has a fallback itself, eg.:

const ObjectWithFallback = v.fallback(
  v.object({ foo: string() }), <-- checks if entries of this object has a fallback
  { foo: "bar" }, <-- completely ignored
);

Copy link

vercel bot commented Apr 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
valibot ❌ Failed (Inspect) Apr 13, 2025 7:20am

Comment on lines 67 to 75

// If it's and object schema and it has a fallback, return it
if (schema.type === 'object' && 'fallback' in schema) {
return schema.fallback as InferFallbacks<TSchema>;
}

// If it is an object schema, return fallbacks of entries
if ('entries' in schema) {
const object: Record<string, unknown> = {};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, it would be like this, however fallback requires all values to be defined.

Suggested change
// If it's and object schema and it has a fallback, return it
if (schema.type === 'object' && 'fallback' in schema) {
return schema.fallback as InferFallbacks<TSchema>;
}
// If it is an object schema, return fallbacks of entries
if ('entries' in schema) {
const object: Record<string, unknown> = {};
// If it is an object schema, return fallbacks of entries
// If an object itself has a fallback, use it
if ('entries' in schema) {
const object: Record<string, unknown> = schema.type === 'object' && 'fallback' in schema ? schema.fallback : {};

eg.

const ObjectWithFallbackSchema = fallback(object({
  foo: number(),
  bar: fallback(number(), 5)
}), {
  foo: 3
});

I would expect bar to not be required, because it itself has a fallback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be achieve by adjusting Fallback type to

/**
 * Fallback type.
 */
export type Fallback<
  TSchema extends BaseSchema<unknown, unknown, BaseIssue<unknown>>,
  TFallbackSchema = MaybeReadonly<InferOutput<TSchema>>
> =
  | {
    [key in keyof TFallbackSchema as TFallbackSchema[key] extends SchemaWithFallback<any, any> ? never : key]: TFallbackSchema[key];
    } & {
      [key in keyof TFallbackSchema as TFallbackSchema[key] extends SchemaWithFallback<any, any> ? key : never]?: TFallbackSchema[key];
    }
  | ((
      dataset?: OutputDataset<InferOutput<TSchema>, InferIssue<TSchema>>,
      config?: Config<InferIssue<TSchema>>
    ) => ({
      [key in keyof TFallbackSchema]: TFallbackSchema[key] extends SchemaWithFallback<any, any>
      ? TFallbackSchema[key]
      : TFallbackSchema[key];
    } & {
      [key in keyof TFallbackSchema as TFallbackSchema[key] extends SchemaWithFallback<any, any> ? key : never]?: TFallbackSchema[key];
    }));

but that's whole other discussion

@@ -64,6 +64,12 @@ export function getFallbacks<
ErrorMessage<TupleWithRestIssue> | undefined
>,
>(schema: TSchema): InferFallbacks<TSchema> {

// If it's and object schema and it has a fallback, return it
if (schema.type === 'object' && 'fallback' in schema) {
Copy link
Owner

@fabian-hiller fabian-hiller Apr 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it enough to just check for 'fallback' in schema? This way we make it the default behaviour for any schema.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, could be done that way too.

But probably this if clause can be removed, and do this when retrieving fallbacks of an object -> #1155 (comment)

Copy link
Owner

@fabian-hiller fabian-hiller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we also need to update the types in library/src/methods/getFallbacks/types.ts to used the exact fallback if available.

@muningis
Copy link
Contributor Author

Good point, definitely need to update the type too. Will do, once decided if fix/change should be implemented/added or not.

@fabian-hiller
Copy link
Owner

If we merge this. Do we consider this a fix or a breaking change and park it in a new v2 branch? I am not really sure. I really wonder why I implemented it the way I did.

@fabian-hiller fabian-hiller added this to the v2 milestone Apr 20, 2025
@fabian-hiller fabian-hiller self-assigned this Apr 20, 2025
@fabian-hiller fabian-hiller added the enhancement New feature or request label Apr 20, 2025
@muningis
Copy link
Contributor Author

IMO it’s breaking change even if it’s a bugfix. Libraries can’t (shouldn’t be able to) afford such changes with minor/patch releases.

@fabian-hiller fabian-hiller added the next version Something to look at for our next major release label Apr 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request next version Something to look at for our next major release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

getFallbacks Fails Wtih Nested Objects
2 participants