typescript - Kan jag sätta ett standardvärde på en prop som typats med en generisk typ


Jag är mycket erfaren med Vue, men jag är nybörjare på TypeScript. Jag har en enkel Checkbox.vue-komponent tillsammans med andra props. Jag har två valfria props, checkedValue och uncheckedValue, som är typade med två generiska typer TCheckedValue och TUncheckedValue. Jag vill ha standardvärden för dessa två props och eftersom en generisk typ per definition kan acceptera vilken typ som helst bör jag kunna sätta checkedValue: true och uncheckedValue: false, men jag får följande fel:

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

Detta är min komponentkod:

<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>

Jag har tillbringat en vecka med chatGPT och Claude AI och försökt lista ut det, men utan framgång.

Vad jag har försökt hittills:

<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,
});

Svar #1

Du kan lägga till standardvärdenas typer till props:

    checkedValue?: TCheckedValue | true;
    uncheckedValue?: TUncheckedValue | false;

Det ger (egenskap) checkedValue: true | NotUndefined<TCheckedValue> vilket verkar rätt.

Du kan också använda det nya sättet att destrukturera props:

const {checkedValue = true, uncheckedValue = false, ...props} = defineProps<{
    label?: string;
    checkedValue?: TCheckedValue;
    uncheckedValue?: TUncheckedValue;
}>();

Det ger checkedValue: true | TCheckedValue vilket också verkar rätt.