Exploring Vue 3.3: Understanding Generics and Dynamic Properties

I'm currently diving into the generics feature in vue 3.3 and I've been pondering about defining the type of an incoming prop based on another prop value.

This is my current component structure:

export interface OptionProps {
  id: string | number;
  name: string;
};
<script setup lang="ts" generic="T extends OptionProps">
import { computed } from "vue";
import {OptionProps} from './types.ts'

// defining props using generics
const props = defineProps<{
  options: T[];
  modelValue: T | T[];
  multiple: boolean;
}>();

// defining emits
const emit = defineEmits<{
  "update:modelValue": [value: T|T[]];
}>();

// setting proxyValue for modelValue to emit update:modelValue
const proxy = computed({
  get() {
    return props.modelValue;
  },
  set(value: T|T[]) {
    emit("update:modelValue", value);
  },
});
</script>
<template>
  <div>---- {{ options }} ----- {{ proxy }}</div>
</template>

The goal here is to limit the type of modelValue depending on the 'multiple' value, meaning:

If multiple is true -> modelValue should be T[] but if it's false, modelValue should be T

I want callers of my component to encounter an error if they try to provide an array as modelValue with multiple being false:

<script setup lang="ts">
import { ref } from 'vue'
import Comp from './Comp.vue';
import { OptionProps } from './types.ts'


const result = ref<OptionProps[]>([{id: undefined, name: undefined}])

</script>

<template>
  <Comp 
  :model-value="result" 
  :options="[{id: 1, name: 'one'}, {id: 2, name: 'two'}]"
   :multiple="false"
   />
</template>

I briefly considered conditional typing, but I'm unsure how to implement it in this scenario. Is it even feasible?

Answer №1

While this may not provide the precise answer to your question, it serves as a workaround that delivers the same desired outcome

You have the option to modify your current component to resemble something similar to this

<script setup lang="ts" generic="T extends OptionProps">
import { computed } from "vue";
import type { OptionProps } from "./types.ts";

// utilize generics to define props
const props = defineProps<{
  options: T[];
  singleModelValue?: T;
  multiModelValue?: T[];
}>();

// define emits
const emit = defineEmits<{
  "update:singleModelValue": [value: T | undefined];
  "update:multiModelValue": [value: T[] | undefined];
}>();

// create proxyValue for singleModelValue to trigger update:modelValue
const singleProxy = computed({
  get() {
    return props?.singleModelValue || undefined;
  },
  set(value: T | undefined) {
    emit("update:singleModelValue", value);
  },
});

// create proxyValue for multiModelValue to trigger update:multiModelValue
const multiProxy = computed({
  get() {
    return props?.multiModelValue || [];
  },
  set(value: T[] | undefined) {
    emit("update:multiModelValue", value);
  },
});
</script>
<template>
  <div>---- {{ options }} ----- {{ singleProxy ?? multiProxy }}</div>
</template>

and implement it like so

<script setup lang="ts">
import { ref } from "vue";
import Comp from "./components/Comp.vue";
import type { OptionProps } from "./components/types.ts";

const single_result = ref<OptionProps>({ id: 1, name: "hello" });
const multi_result = ref<OptionProps[]>([{ id: 1, name: "hello" }]);
</script>

<template>
  <Comp
    :single-model-value="single_result"
    :options="[
      { id: 1, name: 'one' },
      { id: 2, name: 'two' },
    ]"
  />
  <br />
  <Comp
    :multi-model-value="multi_result"
    :options="[
      { id: 1, name: 'one' },
      { id: 2, name: 'two' },
    ]"
  />
</template>

Therefore, instead of utilizing multiple values, you can establish two props – one to manage an array and the other for a non-array value. I trust you will find this information beneficial.

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

The React Native Flatlist encountered an error due to a mismatch in function overloads

I'm currently working on a React Native app using Typescript, and I've encountered an issue with the Flatlist renderItem function. As someone who is new to both Typescript and React Native, I received the following error message: No overload ma ...

Using Angular and Typescript to implement a switch case based on specific values

I am attempting to create a switch statement with two values. switch ({'a': val_a,'b': val_b}){ case ({'x','y'}): "some code here" break; } However, this approach is not functioning as expected. ...

Tips for reducing bundle size in Laravel and Vue while integrating Vuetify

My current setup involves Vue integrated with Laravel. After running npm run production, I noticed that the bundle size is quite large at 1.1MB. This seems to be primarily due to Vuetify, as there are only a few components in use. In previous projects wher ...

The readline interface in Node that echoes each character multiple times

After creating a node readline interface for my project, I encountered an unusual issue. this.io = readline.createInterface({ input: process.stdin, output: process.stdout, completer:(line:string) => { //adapted from Node docs ...

Vue - Seamlessly Editing and Creating Content Together

When using Laravel, I am attempting to pass data to a Vue component. Depending on whether the user enters the component through an edit URL or a create URL, we send either an array of data or null. Here is an example of how this process works: Blade view ...

Add a service to populate the values in the environment.ts configuration file

My angular service is called clientAppSettings.service.ts. It retrieves configuration values from a json file on the backend named appsettings.json. I need to inject this angular service in order to populate the values in the environment.ts file. Specific ...

Guarantee: exclude all successful and unsuccessful responses and only carry out the .finally method

I have a function named request: function request (endpoint) { return axios.request(endpoint).then(api.onSuccess).catch(api.onError) } api.onSuccess: onSuccess (response) { let breakChain = false ... adding some logic here ... return break ...

Preventing over-purchasing products by managing Knex.js inventory levels

Currently, I am in the process of developing an online store for my school's guild organization. I must admit that I lack experience working with databases and Knex.js is still a bit challenging for me. An issue arises when multiple users simultaneo ...

Utilize TypeScript to retrieve the enumeration values as a parameter through a method that employs a generic enum type

Is there a way to retrieve all values of an Enum (specified as a parameter or generic) and return them in a list? Additionally, if the user has a specific role, I only need to retrieve certain Enum values provided as a parameter. I had the idea of groupin ...

What could be causing my date variable to reset unexpectedly within my map function?

Currently, I'm utilizing a tutorial to create a custom JavaScript calendar and integrating it into a React project You can find the functional JavaScript version in this jsfiddle import { useState, useRef, useMemo } from 'react' import type ...

Can a TypeScript generic version of the Y-combinator be successfully executed?

Here is an interesting JavaScript implementation of the Y-combinator: const Y = g => (x => g(x(x)))(x => g(x(x))) //or const Y = f => { const g = x => f(x(x)) return g(g) } I've been thinking, could it be possible to create a TypeS ...

Vue.js does not have the ability to toggle a font-awesome icon

I am having trouble toggling a font awesome icon based on a boolean value. It seems that the font-awesome icon stays on the screen even after it is drawn: Check out this link for reference HTML: <script src="https://unpkg.com/vue"></script> ...

Instructions for creating a function that can receive an array of objects containing a particular data type for the value associated with the key K

Seeking guidance on how to define a specific signature for a function that accepts an array of objects and 3 column names as input: function customFunction<T, K extends keyof T>( dataset: T[], propertyOne: K, propertyTwo: K, propertyThird: K ...

I am interested in utilizing Sequelize, Vue, and Node to implement a query that filters data once it is retrieved to display on my view

Within my project, there's a table tracking user responses to a quiz. By utilizing the following query, I've successfully retrieved all the information from that table and stored it in my TotalQuizResponses array for display: this.totalQuizRespon ...

Vue HeadlessUI Error: The function vue.defineComponent is not recognized

Trying to incorporate @headlessui/vue into my nuxt project has been a challenge. My attempt at using it looks like this: <template> <Menu> <MenuItems> <MenuItem>Item</MenuItem> </MenuItems> </Menu&g ...

You cannot convert a function to a string while utilizing axios get in nuxtServerInit

While attempting to connect my app to the backend using Udemy's Nuxt.js course, I encountered a GET http://localhost:3000/ 500 (Internal Server Error) on the client side with the following code: import Vuex from 'vuex'; import axios from &a ...

I implemented progress bars in Angular 2 that have changing maximum values. The service updates the maximum value for each bar dynamically. Currently, the progress bars are functioning at 100% capacity

this.games=[ {"val":50, "name":"Articlescontributed","max":35}, {"val":30 ,"name":"Articlesrated", "max":999}, {"val":20, "name":"Views", "max":35}, {"val":30, "name":"Ratings", "max":35}, {"val":20, "name":"Follower", "max":200}, { ...

Angular date selection with a range of plus two days, factoring in the exclusion of weekends

I am currently using a mat date picker range with specific logic. The minimum date that a user can select on the calendar is set to + 2 days. For example, if today's date is July 20, 2022, the minimum selectable date would be July 22, 2022. However, ...

Is it possible to host an SSR nuxt.js application on GitHub or GitLab pages?

Can you host a server-side rendering application using nuxt.js (universal ssr mode) with a Firebase backend on GitHub/Gitlab Pages? Gitlab provides an example at nuxt, and I'm curious if the server-side dynamic fetching still functions properly. ...