Typing props
You form don't necessary stays in one component. It's common sense to split your logic into multiple ones.
For this I recommend as a first solution a Pinia
store, so types are infered automatically. You can find it explained here.
But if you can't use Pinia, we'll go though the options.
Typing component props
As Regle's types are complex and based on both your state and your rules, it's hard to replicate manually.
@regle/core
exports all its utility types, it can be long to explain each one of them, so we'll show the simplest way to type your props.
To avoid jungling with complex generic types, you can declare your form in a composable inside a file outside your component, and use this composable to type your props.
import { useRegle } from '@regle/core';
import { email, maxValue, minLength, numeric, required } from '@regle/rules';
export function useMyForm() {
return useRegle(
{ email: '', user: { firstName: '', lastName: '' } },
{
email: { required, email: email },
user: {
firstName: {
required,
minLength: minLength(6),
},
lastName: {
minLength: minLength(6),
},
},
}
);
}
<template>
<input v-model="state.age" placeholder="age" />
<Child :errors="errors" />
</template>
<script setup lang="ts">
import Child from './Child.vue';
import { useMyForm } from './myForm';
const { errors, state } = useMyForm();
</script>
<template>
<ul>
<li v-for="error of errors.email" :key="error">
{{ error }}
</li>
</ul>
</template>
<script setup lang="ts">
import type { useMyForm } from './myForm';
const props = defineProps<{
errors: ReturnType<typeof useMyForm>['errors'];
}>();
</script>
Typing a field prop
It's possible that you have an MyInput
like component that contains your business logic. You may want to pass regle computed properties to this component to display useful information to the user.
Here's how you can do it:
<template>
<div class="my-input">
<input
v-model="modelValue"
:class="{ valid: field.$valid, error: field.$error }"
:placeholder="placeholder"
/>
<ul v-if="field.$errors.length">
<li v-for="error of field.$errors" :key="error">
{{ error }}
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import type { RegleFieldStatus } from '@regle/core';
const modelValue = defineModel<string>();
const props = defineProps<{
field: RegleFieldStatus<string>;
placeholder: string;
}>();
</script>
<template>
<form>
<MyInput v-model="state.name" :field="regle.$fields.name" placeholder="Type your name" />
<MyInput v-model="state.email" :field="regle.$fields.email" placeholder="Type your email" />
</form>
</template>
<script setup lang="ts">
import MyInput from './MyInput.vue';
import { useRegle } from '@regle/core';
import { email, required } from '@regle/rules';
const {regle, state} = useRegle({name: '', email: ''}, {
name: {required},
email: {required, email},
})
</script>