Vue模板声明动态插槽时vue-tsc编译报错求助
问题代码
<template v-for="(_, slotName) in slots" #[slotName]="slotProps"> <slot :name="slotName" v-bind="slotProps"></slot> </template>
编译错误信息
Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type 'Readonly<{ default?: ((arg: { isActive: Ref
; }) => VNode<RendererNode, RendererElement, { [key: string]: any; }>[]) | undefined; activator?: ((arg: { ...; }) => VNode<...>[]) | undefined; }>'. No index signature with a parameter of type 'string' was found on type 'Readonly<{ default?: ((arg: { isActive: Ref
; }) => VNode<RendererNode, RendererElement, { [key: string]: any; }>[]) | undefined; activator?: ((arg: { ...; }) => VNode<...>[]) | undefined; }>'. 3 <template v-for="(_, slotName) in slots" #[slotName]="slotProps">
已尝试但无效的方案
- 通过vue-shim为组件添加类型
- 为$slots添加类型
- 将slotName强制转换为any类型
- 使用any作为泛型声明defineSlots宏
有效解决方案
方案1:显式约束slotName为组件插槽键的联合类型
如果组件已通过defineSlots定义了插槽类型,提取插槽键的联合类型来约束循环变量:
import type { SlotsType } from 'vue'; // 定义组件的插槽类型 type ComponentSlots = SlotsType<{ default: { isActive: Ref<boolean> }; activator: { someProp: string }; }>; // 提取插槽键的联合类型 type SlotKeys = keyof ComponentSlots;
模板中使用类型断言:
<template v-for="(_, slotName) in Object.keys(slots) as SlotKeys[]" #[slotName]="slotProps"> <slot :name="slotName" v-bind="slotProps"></slot> </template>
方案2:为插槽类型添加字符串索引签名
扩展插槽类型,添加字符串索引以兼容任意字符串键:
import type { Slots } from 'vue'; // 扩展Slots类型,添加字符串索引 type IndexableSlots = Slots & { [key: string]: any }; // 在组件中声明slots为该类型 const slots = defineSlots<IndexableSlots>();
方案3:直接在模板中对slotName做精确类型断言
无需修改脚本,直接在模板中对slotName断言为当前slots的键类型:
<template v-for="(_, slotName) in slots" #[slotName as keyof typeof slots]="slotProps"> <slot :name="slotName as keyof typeof slots" v-bind="slotProps"></slot> </template>
内容的提问来源于stack exchange,提问作者vladissick

