One of the most abstract concepts in Vue.j is scoped slots.
When you add the complexities of a typing system like TypeScript, the difficulty can increase.
However, with the macro defineSlots
introduced in Vue 3.3+, adding types to your slots is easier than ever. Let me show you how.
Using defineSlots
The purpose of the macro is to improve Developer Experience (DX) by adding suggestions and type validation directly in your code editor/IDE. defineSlots
accepts a literal type as its parameter, where each property represents the name of a slot, and the value is a function defining the props the slot accepts.
For instance, let's say your actions
slot provides a function called open
:
defineSlots<{
actions(props: { open: () => void }): any; // Return type is currently ignored by the macro
}>();
Additionally, and as a bonus, defineSlots
returns the slots
object you would normally get by calling the useSlots
macro.
Practical Example with defineSlots
Suppose in your AppProducts
component you want to provide product information and define their types.
interface Product {
id: number;
name: string;
price: number;
}
const slots = defineSlots<{
default(props: {
highlight: { // You can use literal types
name: string;
price: number;
};
}): void;
list(props: {
products: Product[];
}): void;
}>();
As you can see, we are declaring the types for two slots:
- In the
default
slot, we expect ahighlight
product withname
andprice
properties. - For the
list
slot, we send a list ofProduct
.
This straightforward approach has a profound impact. On the one hand, we are properly validating the slot types in the AppProducts
component itself. On the other hand, TypeScript will infer the slot types in the “parent” component that uses these slots.
<template>
<AppProduct>
<template #default="{ highlight }">
<h2>{{ highlight.name }} - ${{ highlight.price }}</h2>
</template>
<template #list="{ products }">
<ul>
<li v-for="product in products" :key="product.id">
{{ product.name }} - ${{ product.price }}
</li>
</ul>
</template>
</AppProduct>
</template>
Demo
As always, here’s a demo.