vuelidate: Vite Vue TS intellisense error: Argument of type 'ComputedRef<>' is not assignable to parameter of type 'ValidationArgs<>'

Describe the bug I’m trying out vuelidate 2 alpha with typescript and vite, and there seems to be an issue with the typescript linter complaining about the types ComputedRef<{}> and ValidationArgs<{}>. I was following the instructions provided in making vuelidate rules, and I don’t know why there’s an error with typescript regarding the manner. Is there some sort of thing that I should’ve done that I don’t know about? Like some sort of typecasting?

Reproduction URL I apologise if I wasn’t able to use the provided codesandbox templates provided, since the issue is on vite and not on vue-cli. Provided here is the URL of the code. The issue cannot be seen through codesandbox, and it will only be visible if you check the typescript linting on vscode itself. The file and line in question is on ./src/components/FormComposition.vue on ln 32.

To Reproduce Steps to reproduce the behavior:

  1. Create a new vite project using the terminal using the vue-ts template: yarn create vite --template vue-ts vuelidate-issue-test.
  2. Open the project on VS Code.
  3. Open the VS Code inbuilt terminal and run yarn to initialise the project.
  4. Install vuelidate/core and vuelidate/validators onto the project: yarn add @vuelidate/core @vuelidate/validators.
  5. Create a new vue file component called Form.vue in src/components folder.
  6. Copy the code written below.
// Form.vue

<script lang="ts" setup>
import { useVuelidate } from "@vuelidate/core";
import { required, email, minLength, sameAs } from "@vuelidate/validators";
import { reactive, computed } from "vue";

const state = reactive({
  email: "",
  password: {
    pass: "",
    confirm: "",
  },
});

const rules = computed(() => {
  return {
    email: { required, email },
    password: {
      pass: { required, minLength: minLength(6) },
      confirm: { required, sameAs: sameAs(state.password.pass) },
    },
  };
});

// const rules = {
//   email: { required, email },
//   password: {
//     pass: { required, minLength: minLength(6) },
//     confirm: { required, sameAs: sameAs(state.password.pass) },
//   },
// };

const v$ = useVuelidate(rules, state);

const submitForm = () => {
  // vuelidate validation
  v$.value.$validate();

  // if success
  if (!v$.value.$error) {
    alert("Form Successfully Submitted!");
  }
  // // if fail
  // else {
  //   alert(
  //     "I'm sorry, you seem to not have filled all inputs. Please fill them up and try again."
  //   );
  // }
};
</script>

<template>
  <div class="root">
    <h2>Create an Account</h2>
    <p>
      <input type="text" v-model="state.email" placeholder="Email" />
      <span v-if="v$.email.$error">
        {{ v$.email.$errors[0].$message }}
      </span>
    </p>
    <p>
      <input
        type="password"
        v-model="state.password.pass"
        placeholder="Password"
      />
      <span v-if="v$.password.pass.$error">
        {{ v$.password.pass.$errors[0].$message }}
      </span>
    </p>
    <p>
      <input
        type="password"
        v-model="state.password.confirm"
        placeholder="Confirm Password"
      />
      <span v-if="v$.password.confirm.$error">
        {{ v$.password.confirm.$errors[0].$message }}
      </span>
    </p>
    <button @click="submitForm">Submit</button>
  </div>
</template>
  1. Go back to the App.vue file, and update the file as is:
// App.vue

    <script setup lang="ts">
-    // This starter template is using Vue 3 <script setup> SFCs
-    // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
-    import HelloWorld from './components/HelloWorld.vue'
+    import Form from './components/Form.vue'
    </script>
    
    <template>
-      <img alt="Vue logo" src="./assets/logo.png" />
-      <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
+      <Form />
    </template>

    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
  1. Run the development server using yarn dev.

Expected behavior There are no errors when running it in the development server, but the only issue is that the typescript linter is complaining about incompatible types.

Screenshots where the typescript error shows up

Additional context I was following a tutorial by LearnVue, and when I reached the section where the tutorial is converting the code from the options api to the composition api, and I stumbled upon on how to initialise the useVuelidate() method. When I tried doing it myself, the typescript lint `Argument of type ‘ComputedRef<{email: required…}>’ is not assignable to parameter of type ‘ValidationArgs<{email: string;…}>’.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 3
  • Comments: 23 (7 by maintainers)

Most upvoted comments

Same problem here. I was able to get rid of the error for now with the following (even though I’m sure it’s a bad hack and I’ll change it as soon as there’s a better fix):

const state = ref({
  email: "",
  password: "",
});

const rules = computed(() => ({
  email: {
    required,
    email,
  },
  password: {
    required,
  },
}));

const v$ = useVuelidate(
  rules as unknown as ValidationArgs<{ email: string; password: string }>,
  state
);

i really do hope that they have made a better fix for this though

Same problem here. I was able to get rid of the error for now with the following (even though I’m sure it’s a bad hack and I’ll change it as soon as there’s a better fix):

const state = ref({
  email: "",
  password: "",
});

const rules = computed(() => ({
  email: {
    required,
    email,
  },
  password: {
    required,
  },
}));

const v$ = useVuelidate(
  rules as unknown as ValidationArgs<{ email: string; password: string }>,
  state
);

We write some helper above vuelidate@next and use this interface

export type ValidationArgs<T = unknown> = {
  [key in keyof T]: T[key] extends Record<string, unknown>
    ? ValidationArgs<T[key]>
    : Record<string, ValidationRule<T[key]>>
}

Actual realization is wrong and approve this code

// Current
useVuelidate({
  password: required,
  passwordConfirmation: required,
}, {
  password: '',
  passwordConfirmation: '',
});

// What expected by doc
useVuelidate({
  password: {
    required,
  },
  passwordConfirmation: {
    required,
  },
}, {
  password: '',
  passwordConfirmation: '',
});

https://github.com/vuelidate/vuelidate/blob/a9eb302e668c5514500edda9a96857410e3332e9/packages/vuelidate/index.d.ts#L60-L62

Going to close for now. If ppl still have issues with latest version will reopen