valibot icon indicating copy to clipboard operation
valibot copied to clipboard

Schema type with optional properties

Open LucasDemea opened this issue 7 months ago • 6 comments

I'm trying to write a type for schemas. My use case is i'm coding a library where developers will be able to define a schema property, which should be constrained to a certain type. A kind of meta-schema. Every property of this object is optional.

Minimal example:

Type TSchema = ObjectSchema<
  Partial<{
    foo: StringSchema<undefined>;
    bar: NumberSchema<undefined>;
    baz: BooleanSchema<undefined>;
  }>,
  undefined
>;

schema : TSchema = v.object({
    foo: v.string(),
    baz: v.boolean(),
  }),
};

This doesn't work because ObjectSchema seems not to allow potentially undefined properties. Is there a consistent way to write schema types (not infer them) ? What would be the best way to solve this ?

LucasDemea avatar Apr 15 '25 13:04 LucasDemea

The TS error I get is Types of property ''~standard'' are incompatible.

LucasDemea avatar Apr 15 '25 16:04 LucasDemea

You could (probably should) use BaseSchema -> Playground Link

However, it would be highly advised to use Standard Schema -> Playground Link

Unfortunately however, when using extends you can restrict schema to specific keys (or I couldn't manage that)

muningis avatar Apr 15 '25 17:04 muningis

Thanks for reaching out! And thanks @muningis for your help! We could try to improve our internal InferObjectInput and InferObjectOutput types to solve this problem. Also, does it work to use GenericSchema (which is the same as BaseSchema with optional generics)? This would simplify your code:

import * as v from 'valibot';

type MySchema = v.GenericSchema<
  Partial<{
    foo: string;
    bar: number;
    baz: boolean;
  }>
>;

const schema: MySchema = v.object({
  foo: v.string(),
  baz: v.boolean(),
});

fabian-hiller avatar Apr 16 '25 04:04 fabian-hiller

Thank you for your help. This works but is a bit too permissive, as it allows to write:

const schema: MySchema = v.object({
  foo: v.string(),
  qux: v.boolean(),
});

Where qux is a property which wasn't declared in MySchema

LucasDemea avatar Apr 16 '25 08:04 LucasDemea

This is limitation of Typescript. Type parameters can do extend (allows widening) type, but not satisfies (strict object type)

muningis avatar Apr 16 '25 08:04 muningis

I think ArkType solved it with their declare API. We should look into it. See issue #3 for more context.

fabian-hiller avatar Apr 17 '25 03:04 fabian-hiller

Hi, @LucasDemea. I'm Dosu, and I'm helping the Valibot team manage their backlog. I'm marking this issue as stale.

Issue Summary:

  • You are seeking advice on defining a TypeScript type for schemas with all optional properties.
  • ObjectSchema does not support properties that may be undefined.
  • Suggestions included using BaseSchema, Standard Schema, and GenericSchema, but each had limitations.
  • ArkType's declare API was mentioned as a potential solution to explore further.

Next Steps:

  • Please confirm if this issue is still relevant to the latest version of the Valibot repository by commenting here.
  • If there is no further activity, this issue will be automatically closed in 30 days.

Thank you for your understanding and contribution!

dosubot[bot] avatar Jul 17 '25 16:07 dosubot[bot]