Utilizing Vue 3/Nuxt 3 Scoped Slots to Automatically Deduce Generic Data Types from Props

I am looking to incorporate a carousel component into Nuxt v3. The component will be passed an array of items, focusing solely on the logic without handling styling or structuring.

Currently, this is what my component looks like:

components/tdx/carousel.vue

<template>
  <div>
    <slot name="last"></slot>
    <div v-for="item in items">
      <slot
        name="item"
        v-bind="item"
      ></slot>
    </div>
    <slot name="next"></slot>
  </div>
</template>

<script setup lang="ts">
const props = defineProps({
  items: {
    type: [],
    required: true,
  },
  spotlight: {
    type: Number,
    default: 1,
    validator(value: number) {
      return value > 0;
    },
  },
});
</script>

The specifics of the carousel's logic are not crucial at this point.

In the parent component, I can utilize the component as follows:

<template>
  <div class="container">
    <TdxCarousel :items="exampleArray">
      <template #item="{ title, description }">
        <p class="font-semibold text-2xl">{{ title }}</p>
        <hr />
        <p>{{ description }}</p>
      </template>
    </TdxCarousel>
  </div>
</template>

<script setup lang="ts">
const exampleArray = ref([
  {
    title: 'Item 1',
    description: 'Desc of item 1',
  },
  {
    title: 'Item 2',
    description: 'Desc of item 2',
  },
]);
</script>

Although this setup works well, I am aiming to include typings for better code clarity. As the types of title and description are currently set to any due to the items' type being unknown[] in the props of carousel.vue.

I came across this article demonstrating how to create a generic component, but I prefer to avoid it as it could interfere with nuxt's auto import system.

Is there a way to infer types from the provided items in the carousel.vue props without resorting to generics?

Answer №1

Latest Update: May 2023

Exciting news for Vue developers! With the release of Vue 3.3, generic components have received official support.

To make use of this feature, you'll need to define a generic parameter in your components. Update your carousel.vue component by adding the generic attribute within the <script setup> tag. Also, ensure you utilize the type-based method for defineProps to properly handle the generics.

<script setup lang="ts" generic="T extends any">
withDefaults(
  defineProps<{ items: T[]; spotlight?: number }>(), {
  spotlight: 1,
});
</script>
<template>
  <div>
    <slot name="last"></slot>
    <div v-for="item in items">
      <slot
        name="item"
        v-bind="item">
      </slot>
    </div>
    <slot name="next"></slot>
  </div>
</template>

By following these steps, the props on the slot will be correctly inferred based on the type of items provided.

https://i.sstatic.net/JLdnj.png

https://i.sstatic.net/zxyIj.png

Previous Versions Information

In older versions of VSCode/Volar, enabling an experimental flag was necessary. This involved activating the experimentalRfc436 option in your tsconfig.json file under vueCompilerOptions.

// tsconfig.json
{
  // ...
  "vueCompilerOptions": {
    "experimentalRfc436": true
  }
}

This additional step is no longer required as recent versions of Volar come with this feature enabled by default.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Vue automatically refreshes momentjs dates prior to making changes to the array

I am dealing with a situation where my child component receives data from its parent and, upon button click, sends an event to the parent via an event bus. Upon receiving the event, I trigger a method that fetches data using a Swagger client. The goal is ...

Customize the group headers and item rows in a Vuetify 2 data table with grouped data

One of my objectives is to generate a Vuetify 2 data table displaying a list of car models grouped by vendor, with customized headers for each group and customized item rows for each car model. My main issue lies in the fact that Vuetify seems to completel ...

Having trouble with firebase admin code completions not functioning properly in vscode?

I've attempted to install the Typescript integration for Firebase using: npm install --save-dev @types/firebase Unfortunately, I have not had any success. The "firebase-admin" and "firebase-functions" packages do not provide code completion or intel ...

Vue component does not inherit scoped CSS

One issue I encountered involves a scoped style tag in my Vue component: <style scoped> .ttt{ background-color: red; } </style> After building the project with npm and webpack, the styles were not being copied over. To address ...

Retrieving information from MongoDB and Electron JS through IPC renderer

programming file this.$electron.ipcRenderer.send('get-result') this.$electron.ipcRenderer.on('got-it', (event, data) => { if (data.status) { this.allResult = data.result } else{ thi ...

The expansion feature of PrimeNG Turbotable

I'm currently facing an issue with the Primeng Turbotable where I am unable to expand all rows by default. You can find a code example of my problem at this link. I have already tried implementing the solution provided in this example, but unfortuna ...

Transforming Typescript types into object literals

type SelectData = { name?: boolean; address?: boolean; } const selectData: SelectData = { name: true } const untypedSelectData = { name: true } I am looking to enforce TypeScript to throw an error if there is an attempt to assign a property that ...

Guide on transforming JSON data into a collection of custom objects using TypeScript

When working with raw data in TypeScript (originally a JSON file and imported using import * as raw_data from './json_file.json'): let raw_data: object = {"a": {"name": "Name a", "desc": "Description a ...

What is the most effective approach to create an API for a large dataset and access it using Vue.js?

I am in the process of creating an API for my WordPress site to retrieve all posts from a custom post type. However, I have encountered some challenges and would appreciate any ideas or solutions that align with best practices. The custom post type contai ...

Creating a Dynamic Clear Button for a Text Area in Angular

Working on my Angular application, I have implemented a form with a textarea element. My goal is to incorporate a clear button inside the textarea element that should: Appear only when the textarea is focused Disappear when the textarea is out of focus ( ...

Typescript fill() function like Laravel's fill()

One interesting feature in Laravel is the fill() method of every database model, which only assigns fields marked as "mass assignable" to the class property. (https://laravel.com/docs/5.8/eloquent#mass-assignment) public class Rectangle { protected $f ...

Exploring TypeScript: Implementing a runtime data mapping in place of an interface

Take a look at this code snippet that defines two command handlers for a server: import { plainToClass } from "class-transformer"; enum Command { COMMAND_1, COMMAND_2, } class Command1Data { foo1!: string } class Command2Data { foo2!: ...

Experimenting with Vuejs by testing a function that delivers a Promise upon the execution of the "Created" hook

In my Vuejs application, I have the following script written in Typescript: import { Foo, FooRepository } from "./foo"; import Vue from 'vue'; import Component from 'vue-class-component'; import { Promise } from "bluebird"; @Component ...

Using TypeScript and the `this` keyword in SharePoint Framework with Vue

I'm currently developing a SharePoint Framework web part with Vue.js. Check out this code snippet: export default class MyWorkspaceTestWebPart extends BaseClientSideWebPart<IMyWorkspaceTestWebPartProps> { public uol_app; public render(): ...

What is the solution for addressing the deprecation warning "The 'importsNotUsedAsValues' flag will no longer work in TypeScript 5.5"?

Is anyone familiar with how to resolve this tsconfig error? The flag 'importsNotUsedAsValues' is outdated and will no longer work in TypeScript 5.5. To address this error, use 'ignoreDeprecations: "5.0"' or switch to using & ...

How to Retrieve a Global Variable in an Angular Template

Is there a way to access a global variable from an Angular template? let unableToAccess = false; @Component({ selector: 'app-payment', templateUrl: './buy.component.html', styleUrls: ['./buy.component.scss'] }) export ...

Sending JSON object arrays from Vue.js to Laravel using AXIOS: A Step-by-Step Guide

My Laravel API endpoint needs to receive the following format in order to successfully add it to the database: { ICAO: 'ABC', name: 'The name of Airport', place: 'city', country: 'country' } I have created ...

Retrieve a targeted data value from a JSON object based on an array value

Looking at the JSON array and another array provided below. JSON OBJECT { id: 1, name: 'abc', email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dfbebdbc9fb8b2beb6b3f1bcb0b2">[emai ...

The problem with the "typescript-react-apollo" codegen plugin is that it is declaring block-scope variables more than once in the generated

Recently, I embarked on a new project utilizing NextJS with graphql-codegen to auto-generate my apollo-react types from the API. Unfortunately, it seems to be generating duplicate exported variables right from the start, causing a typescript error and hi ...

The Unit Test for Angular NgRx is not passing as expected

I'm facing difficulties with my unit tests failing. How can I verify that my asynchronous condition is met after a store dispatch? There are 3 specific checks I want to perform: 1/ Ensure that my component is truthy after the dispatch (when the cond ...