vee-validate icon indicating copy to clipboard operation
vee-validate copied to clipboard

[TypeScript] ObjectSchema with optional properties creates invalid errors object type

Open dabernathy89 opened this issue 10 months ago • 1 comments

What happened?

This might be a niche issue, and I'm not sure if the problem lies with yup's ObjectSchema or vee-validate's toTypedSchema.

We use both of these to help ensure type safety and ensure that our validators match up with our types.

However, when the original type/interface has an optional property, the entire errors object returned by useForm becomes invalid.

Example code (also available at this CodeSandbox link):

<script setup lang="ts">
import { ObjectSchema, object, string } from "yup";
import { useForm } from "vee-validate";
import { toTypedSchema } from "@vee-validate/yup";

type MyObjModel = {
  name: string;
  description?: string;
};

const schema: ObjectSchema<MyObjModel> = object({
  name: string().required("Name is required").min(5),
  description: string(),
});

const { defineField, errors, handleSubmit } =
  useForm({
    validationSchema: toTypedSchema(schema),
  });

const [name, nameProps] = defineField("name");
const [description, descriptionProps] = defineField("description");

const clickSubmit = handleSubmit((values) => {
  console.log({ values });
});
</script>

<template>
  <h1>Name</h1>
  {{ errors.name }}
  <input type="text" v-bind="nameProps" v-model="name" />
  <br />
  <h1>Description</h1>
  {{ errors.description }}
  <textarea v-model="description" v-bind="descriptionProps" />
  <br />

  <button @click="clickSubmit">Submit</button>
</template>

You'll see that simply trying to access any properties on the errors object causes a TypeScript error:

Property 'name' does not exist on type 'Partial<Record<unknown, string | undefined>>'.

Changing the optional property to required (and adding defined() to the schema for that property) clears the TypeScript errors.

Image

Reproduction steps

  1. Create a TypeScript object type with an optional (?) property
  2. Create a yup schema using the ObjectSchema helper
  3. Try to use the errors property returned by useForm and toTypedSchema ...

Version

Vue.js 3.x and vee-validate 4.x

What browsers are you seeing the problem on?

  • [ ] Firefox
  • [ ] Chrome
  • [ ] Safari
  • [ ] Microsoft Edge

Relevant log output

Property 'name' does not exist on type 'Partial<Record<unknown, string | undefined>>'.

Demo link

https://codesandbox.io/p/devbox/youthful-dijkstra-kxtppc

Code of Conduct

  • [x] I agree to follow this project's Code of Conduct

dabernathy89 avatar Feb 20 '25 20:02 dabernathy89

While it would be great if this worked, I understand it's probably pretty tricky. A workaround is to use satisfies:

const schema = object({
  name: string().required('Name is required').min(5),
  description: string(),
}) satisfies ObjectSchema<MyObjModel>;

dabernathy89 avatar Feb 20 '25 20:02 dabernathy89