Vue模板作用域插槽属性的类型推断与断言方案
在Vue TypeScript项目中为作用域插槽推断/指定类型
方案一:让组件支持泛型,自动推断插槽类型
通过给表格组件定义泛型Props,可以让组件根据传入的items类型自动推断作用域插槽的参数类型,无需手动断言。
修改AppTable.vue:
<script setup lang="ts" generic="T extends { id: number }"> // 定义泛型T,要求T必须包含id属性(匹配v-for的key需求) defineProps<{ items: T[]; }>(); </script> <template> <table> <thead> <slot name="thead"></slot> </thead> <tbody> <tr v-for="(item, index) in items" :key="item.id"> <slot name="tbody" :item="item" :index="index"></slot> </tr> </tbody> </table> </template>
在App.vue中使用:
此时无需修改模板代码,当传入customers: Customer[]时,组件会自动将插槽的item类型推断为Customer,类型检查正常通过:
<script setup lang="ts"> import AppTable from './AppTable.vue'; interface Customer { id: number; name: string; email: string; } const customers: Customer[] = [ { id: 1, name: 'John', email: 'john@example.com' }, { id: 2, name: 'Jim', email: 'jim@example.com' }, { id: 3, name: 'Jack', email: 'jack@example.com' }, ]; </script> <template> <div style="margin-bottom: 2rem"> <app-table :items="customers"> <template #thead> <th>ID</th> <th>Name</th> <th>Email</th> </template> <template #tbody="{ item: customer, index }"> <td>{{ index + 1 }}</td> <td>{{ customer.name }}</td> <td>{{ customer.email }}</td> </template> </app-table> </div> </template>
方案二:手动在模板中断言类型
如果无法修改组件(比如第三方组件),可以在模板中使用as关键字手动断言类型,绕过类型不兼容的问题:
<template #tbody="{ item: customer, index }"> <td>{{ index + 1 }}</td> <td>{{ (customer as Customer).name }}</td> <td>{{ (customer as Customer).email }}</td> </template>
这种方式不需要修改组件代码,但需要每次使用时手动断言,适合临时场景。
为什么原来的写法会报错?
之前尝试给插槽参数直接加类型注解的方式失败,是因为组件定义的items是unknown[],所以插槽传出的item类型是unknown。TypeScript不允许将unknown直接赋值给Customer类型(类型不安全),因此会抛出类型不兼容的错误。
而使用any虽然能解决错误,但会完全丢失类型检查,不符合TypeScript的编码规范,不推荐使用。
内容的提问来源于stack exchange,提问作者Christhofer Natalius
相关产品推荐
相关产品推荐

