Discovering the right category for a general component: A step-by-step guide

How about creating a new list component that can work with an array of objects?

<script setup lang="ts">
const props = defineProps<{
  items: Record<string, unknown>[],
  selected: Record<string, unknown> | null
  field: string
}>()
const emit = defineEmits<{
  (e: 'update:selected', value: Record<string, unknown> | null): void
}>()
</script>
<template>
  <div v-for="(item,idx) in items" :key="idx">
    <div 
         @click="emit('update:selected',item)" 
         style="cursor: pointer">
      {{ item[field] }}
    </div>
  </div>
</template>

Let's test it out using a list of employees.

<script setup lang='ts'>
import MyList from './MyList.vue'
import {Ref, ref} from "vue";
interface Employee {
  name: string;
  age: number;
}
const employees: Employee[] = [
  {name: 'Mike', age: 34},
  {name: 'Kate', age: 19},
  {name: 'Den', age: 54},
]
const selectedEmployee=ref<Employee | null>(null)
</script>
<template>
  Age: {{selectedEmployee?selectedEmployee.age:'not selected'}}
  <MyList :items="employees" v-model:selected="selectedEmployee" field="name"/>
</template>

So far everything seems to be functioning well. However, during a build process, there is an error TS2322: “Type 'Employee' is not assignable to type 'Record<string, unknown>'". An update with a generic component might be the solution, but it's not available yet. What would be the best approach to resolve this issue? vue playground

Answer №1

Creating a method is completely doable.

export const wrapSelected = <T>(value: Ref<T | null>) => {
    return computed<Record<string, unknown> | null>({
        get: () => value.value as unknown as (Record<string, unknown> | null),
        set: (val: Record<string, unknown> | null) => {
            value.value = val as unknown as T | null
        }
    })
}

App.vue

...
const wrapperSelected=wrapSelected(selectedEmployee)
</script>

<template>
  Age: {{ selectedEmployee ? selectedEmployee?.age : 'not selected' }}
  <my-list :items="wrapperItems" v-model:selected="wrapperSelected" field-name="name"/>
</template>

Despite not being the most visually pleasing code, it's still an improvement from using any types.

Answer №2

Instead of using unknown, I recommend utilizing any. In the context of your MyList component:

const props = defineProps<{
  items: Record<string, any>[],
  selected: Record<string, any> | null
  field: string
}>()
const emit = defineEmits<{
  (e: 'update:selected', value: Record<string, any> | null): void
}>()

You can explore the distinction between any and unknown in this insightful discussion. Unless there is a specific requirement for unknown, opting for any could be a viable solution.

'unknown' vs. 'any'

Answer №3

After much effort, the issue has been successfully resolved. The latest version of Vue (3.3) now includes support for Generic Components. Check out more information here:

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

Signatures overburdened, types united, and the call error of 'No overload matches'

Consider a TypeScript function that takes either a string or a Promise<string> as input and returns an answer of the same type. Here's an example: function trim(textOrPromise) { if (textOrPromise.then) { return textOrPromise.then(val ...

What is the best way to implement record updates in a nodejs CRUD application using prisma, express, and typescript?

Seeking to establish a basic API in node js using express and prisma. The schema includes the following model for clients: model Clients { id String @id @default(uuid()) email String @unique name String address String t ...

Too many open files error encountered in Watchpack (watcher) - NextJS

Encountering an issue with watchpack resulting in the error messages shown above while running a next app using next dev. The error message is displayed continuously on the screen as follows: Watchpack Error (watcher): Error: EMFILE: too many open files, w ...

Tips for integrating tsconfig with webpack's provide plugin

In my project, I have a simple component that utilizes styled-components and references theme colors from my utils.tsx file. To avoid including React and styled-components in every component file, I load them through WebpackProvidePlugin. Everything works ...

Updating the value of a variable in a separate file with Node.js

I'm facing a business scenario that can be likened to a challenging situation. To simplify, here's the problem: File1.ts import * from 'something'; export const var1="value of var1"; //assume there is a variable 'x' ...

Troubleshooting: JavaScript code not functioning properly with variable input instead of fixed value

I have encountered an issue with a JS function that I'm using. The function is shown below: // A simple array where we keep track of things that are filed. filed = []; function fileIt(thing) { // Dynamically call the file method of whatever ' ...

Generating dynamic slots in VueJS allows for the creation of

Creating slots dynamically from an array is my current task. After some tinkering, I've managed to make it work using the following code snippet: <template v-for="(department,id) in departments" v-slot:[id]="record"> < ...

Converting keyValue format into an Array in Angular using Typescript

Is there a way to change the key-value pair format into an array? I have received data in the following format and need to convert it into an array within a .TS file. countryNew: { IN: 159201 BD: 82500 PK: 14237 UA: 486 RU: 9825 } This needs to be transf ...

Troubleshooting responsive navigation bar in VueJs: Why are elements not appearing when ToggleButton is clicked?

I'm developing a VueJs single page application and I'm struggling to implement a responsive NavBar. No matter what I try, it just doesn't seem to work as expected. I've experimented with several solutions, and the closest I have come t ...

Adding JSON content to a form for editing functionality within an Angular 8 CRUD application

I am currently working on building a Single Page Application using Angular 8 for the frontend and Laravel for the backend. I have been able to successfully pass data to the backend via JWT, and everything is functioning as expected. The application follows ...

You are unable to apply 'use client' on a layout element in Next.js

While attempting to retrieve the current page from the layout.txt file, I encountered errors after adding 'use client' at the top of the page: Uncaught SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data parseMod ...

Could you provide insight into the reason behind debounce being used for this specific binding?

function debounce(fn, delay) { var timer return function () { var context = this var args = arguments clearTimeout(timer) timer = setTimeout(function () { fn.apply(context, args) }, delay) ...

Angular Material's dialog modal swiftly closes without delay

Could you please explain why the modal opens and then closes instantly when I click on the Create Project button? https://example.com/edit/angular-code I am trying to display a component within the modal using Angular Material. portafolio.component.ts ...

Encountering a glitch while integrating the angular-select2 module into an Ionic 3 application

Attempting to integrate the angular-select2 npm module into my ionic 3 app. Successfully installed the module using npm within my project Imported the package into my app.module.ts file Added <select2> tags into the html file of my application Enc ...

Is it possible for NodeJS to prioritize IPv6 DNS lookups as the default option?

In my work with multiple TypeScript (NodeJS 14) client applications that are all Dockerized, I primarily use axios for most HTTP requests. However, there are other tools used as well. Typically, DNS queries default to resolving IPv4 addresses, resulting i ...

Vue Subroutes within nested components do not automatically load

My application features a sidebar that I want to utilize to load the Patient view by default when accessing patient/:id. This should also trigger the loading of the PatientDashboard sub-view. Within the Patient view component, there is a router-view that ...

Authentication for file uploads in Angular 2 using Dropzone and passportjs

I am currently working on implementing authentication for an admin user using Express, Passport, and MySQL in a specific page. The authentication process works fine, but I am facing an issue with verifying whether the user is logged in while uploading file ...

Tips for creating a custom script in my React Native application

My React Native app requires a script to generate static files during the release process. The app is a game that utilizes pre-computed boards, which are resource-intensive to compute. Therefore, I am developing a script that will create these boards and s ...

What to do when the 'image' property in Next.js next/image has an implicit 'any' type and needs fixing?

I'm a newcomer to Next.js and TypeScript and I can't seem to find any helpful resources on resolving this particular issue: import Image from 'next/image'; export default function Item({ image }) { // <-- parameter image needs a &ap ...

Having difficulties with installing the most recent version of nodejs

I've attempted various methods, such as using nvm, but I'm stuck with an outdated version of nodejs (v10). Any suggestions on how to update it? Err:12 http://ppa.launchpad.net/ubuntu-vn/ppa/ubuntu focal Release 404 Not Found [IP: ...