Samuel M. Bednarz
Samuel M. Bednarz

Reputation: 198

How to get a component type so I can use it in a typescript interface - Vue 3

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?

example of what I want

Upvotes: 11

Views: 13500

Answers (2)

husayt
husayt

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

tony19
tony19

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>

demo

Upvotes: 31

Related Questions