Reputation: 198
I'm just trying to setup an array of components so I can do some dynamic component switching later. But I'm stuck at getting Typescript to work with it and no matter what way I ask the question online all the previous answers are all about completely different things.
I've provided a screenshot of what I want to do. I want to be able to write a typescript interface and give it some type which corresponds to any vue component I pass. It just needs to make sure that it's a vue component being passed, I don't care what component it is. I basically need a vue component type definition. How do I do that?
Upvotes: 11
Views: 13500
Reputation: 15139
Here is a detailed example of dynamic type-safe component loading as it is tricky to get right.
You can use generic Component<PropType>
type to define components with similar parameters.
So for instance, to dynamically load all components of certain type you can use this loader
function.
type FilterCompName = "EasyFilter" | "NameFilter"
type Proptype = { filter: string }
type FilteredComponent = Component<Proptype>
function loader<FilteredComponent>(comp: FilterCompName ): FilteredComponent {
return defineAsyncComponent(() => import(`./comps/${comp}.vue`))
}
Then you will have mapping array
type FilterNames= "easyFilter" | "nameFilter"
const comps: { [id in FilterNames]: FilteredComponent} = {
"easyFilter": loader("EasyFilter"),
"nameFilter": loader("NameFilter")
} as const
Then just define ref for name and computed for the dynamically loaded async component
const filterString= ref<string>("test")
const name = ref<FilterNames>("easyFilter")
const ViewComp: ComputedRef<FilteredComponent> = computed(() => comps[name .value])
Then in template section you get dynamic component with correctly typed propertis
<template>
<component :is="ViewComp" :filter="filterString" />
</template>
Here is a working example
Upvotes: 0
Reputation: 138286
Component
is indeed the correct type, as you've attempted, but you need to import it before use:
<script setup lang="ts">
import type { Component } from 'vue'
⋮
interface Props {
header?: Component
body?: Component
footer?: Component
}
const fragments: Props = {
header: FragProfile,
body: FragSubject,
footer: TypeSection
}
</script>
Upvotes: 31