I'm very experienced with Vue, but I'm a typescript beginner. I have a simple Checkbox.vue component alongside other props I have two optional props checkedValue and uncheckedValue that are typed by two generics TCheckedValue and TUncheckedValue. I what to have default values for these two props and since by definition a generic can accept any type i should be able to set checkedValue: true and uncheckedValue: false but I get the next error:
Vue: Type true is not assignable to type
InferDefault<LooseRequired<{
label: string;
checked: boolean;
indeterminate: boolean;
checkedValue?: TCheckedValue | undefined;
uncheckedValue?: TUncheckedValue | undefined;
error: boolean;
}>, TCheckedValue | undefined> | undefined
checkedValue?: InferDefault<LooseRequired<{
label: string
checked: boolean
indeterminate: boolean
checkedValue?: TCheckedValue
uncheckedValue?: TUncheckedValue
error: boolean
}>, TCheckedValue | undefined> | undefined
This is my component code:
<template>
<div>
<input
type="checkbox"
:id="props.id"
:class="[
'rounded dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-sm',
'focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800 mr-2'
]"
:value="props.checkedValue"
:checked="isChecked"
:indeterminate="props.indeterminate"
v-bind="$attrs"
@change="update"
/>
<InputLabel :inline="true" :for="props.id" :value="props.label" />
</div>
</template>
<script setup lang="ts" generic="TCheckedValue, TUncheckedValue">
import { type InputPropsType } from "@/Composeables/useFormInput";
import { computed } from "vue";
import InputLabel from "@/Components/Form/InputLabel.vue";
const props = withDefaults(defineProps<InputPropsType & {
label: string;
checked: boolean;
indeterminate: boolean;
checkedValue?: TCheckedValue;
uncheckedValue?: TUncheckedValue;
error: boolean;
}>(), {
checked: false,
indeterminate: false,
checkedValue: true,
uncheckedValue: false,
error: false,
});
const emit = defineEmits<{
(event: 'change', value: TCheckedValue | TUncheckedValue): void
}>();
const inputValue = defineModel<TCheckedValue | TUncheckedValue>();
const update = (e: Event) => {
const target = e.target as HTMLInputElement;
inputValue.value = target.checked ? props.checkedValue : props.uncheckedValue;
emit('change', inputValue.value);
};
const isChecked = computed(() =>
inputValue.value === props.checkedValue || props.checked
);
</script>
I've spent a week with chatGPT and claude AI trying to figure it out and no joy.
What i tried so far:
<script setup lang="ts" generic="TCheckedValue extends boolean, TUncheckedValue extends boolean">
<script setup lang="ts" generic="TCheckedValue extends boolean = boolean, TUncheckedValue extends boolean = boolean">
<script setup lang="ts" generic="TCheckedValue = boolean, TUncheckedValue = boolean">
// i've also tried to use unknown and any instead of boolean
const props = withDefaults(defineProps<InputPropsType & {
// ...
checkedValue?: TCheckedValue;
uncheckedValue?: TUncheckedValue;
}>(), {
// ...
checkedValue: true as unknown as TCheckedValue,
uncheckedValue: false as unknown as TUncheckedValue,
});
You could add the default values' types to the props:
checkedValue?: TCheckedValue | true;
uncheckedValue?: TUncheckedValue | false;
That gives (property) checkedValue: true | NotUndefined<TCheckedValue>
which seems right.
You could also use the new way of destructuring props:
const {checkedValue = true, uncheckedValue = false, ...props} = defineProps<{
label?: string;
checkedValue?: TCheckedValue;
uncheckedValue?: TUncheckedValue;
}>();
That gives checkedValue: true | TCheckedValue
which also seems right.