You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue+TypeScript泛型类型Props如何设置默认值?

Vue3 + TypeScript 泛型Checkbox组件默认值类型错误解决方案

问题背景

熟练使用Vue,但刚接触TypeScript。编写Checkbox.vue组件时,为checkedValue和uncheckedValue两个可选props定义了泛型TCheckedValue、TUncheckedValue,尝试设置默认值true和false时出现类型错误:

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

组件原代码

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

已尝试但无效的方法

  • 泛型约束为boolean:<script setup lang="ts" generic="TCheckedValue extends boolean, TUncheckedValue extends boolean">
  • 泛型带默认boolean约束:<script setup lang="ts" generic="TCheckedValue extends boolean = boolean, TUncheckedValue extends boolean = boolean">
  • 直接指定泛型默认类型:<script setup lang="ts" generic="TCheckedValue = boolean, TUncheckedValue = boolean">
  • 使用unknown/any替代boolean,并配合类型断言:checkedValue: true as unknown as TCheckedValue

有效解决方案

方法一:泛型默认类型+精准类型断言

核心是给泛型指定默认类型,同时用类型断言让TypeScript认可默认值与泛型的兼容性,再通过非空断言处理可选props的undefined问题:

<script setup lang="ts" generic="TCheckedValue = boolean, TUncheckedValue = boolean">
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,
    // 直接断言为泛型类型,替代unknown中转
    checkedValue: true as TCheckedValue,
    uncheckedValue: false as TUncheckedValue,
    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;
    // 非空断言消除undefined警告,因为已设置默认值
    inputValue.value = target.checked ? props.checkedValue! : props.uncheckedValue!;
    emit('change', inputValue.value);
};

const isChecked = computed(() =>
    inputValue.value === props.checkedValue || props.checked
);
</script>

关键细节

  1. 泛型默认类型:TCheckedValue = boolean确保用户不指定自定义类型时,组件默认使用boolean,与默认值类型匹配。
  2. 类型断言:true as TCheckedValue直接告诉TypeScript,默认值符合泛型类型要求,避免类型不兼容报错。
  3. 非空断言:props.checkedValue!利用默认值的存在,消除可选props的undefined类型警告,保证类型安全。

方法二:泛型约束+默认类型(限制取值范围)

如果需要限制checkedValue/uncheckedValue只能是特定类型(如boolean、string、number),可以给泛型添加约束:

<script setup lang="ts" generic="TCheckedValue extends boolean | string | number = boolean, TUncheckedValue extends boolean | string | number = boolean">
// 其余代码与方法一完全一致
</script>

这种方式既保留了泛型的灵活性,又避免了传入完全不兼容的类型,进一步提升组件的类型安全性。


内容的提问来源于stack exchange,提问作者Andy BnOne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 07:48:10