Implementing Different Interfaces for a Typescript Object in Vue 3

If I have the following TypeScript interfaces, how do I define user to accept either the Baseball, Basketball, or Football interface, each with varying properties?

Currently, only the overlapping properties are accessible. In this case, it is user.stats.A.

I am using Vue 3's Composition API.


interface Profile {
   firstName: string
   lastName: string
   status: string
}

export interface Baseball extends Profile { 
    stats { 
        A: string
        B: string
        ...
    }
}

export interface Basketball extends Profile {
    stats { 
        A: string
        C: string
        ...
    }
}

export interface Football extends Profile {
    stats { 
        A: string
        D: string
        ...
    }
}
setup(){
    const user = reactive<Baseball | Basketball | Football>({
        firstName: 'Michael'
        lastName: 'Jordan'
        status: 'GOAT'
        stats: {
            ...basketball specific properties
        }
    }
})

Answer №1

Your current setup is on the right track and you have followed the correct approach. It's important to ensure that you provide at least the necessary properties from the interface of the union type. Consider structuring your code like this:

// IUser Interface
type IUser = Baseball | Basketball | Football;

If you're uncertain about the object you are dealing with, the best practice is to test for the required properties.

Here is a detailed explanation of a custom XOR type that could be beneficial in restricting objects to have only the properties of one specific interface.

type Without < T, U > = {
  [P in Exclude < keyof T, keyof U > ] ? : never
};
type XOR < T, U > = (T | U) extends object ? (Without < T, U > & U) | (Without < U, T > & T) : T | U;

interface Profile {
  firstName: string
  lastName: string
  status: string
  stats: XOR < XOR < Baseball, Basketball > , Football >
}

export interface Baseball {
  A: string
  B: string
}

export interface Basketball {
  A: string
  C: string
}

export interface Football {
  A: string
  D: string
}



type IUser = Profile

const user: IUser = {
  firstName: 'Michael',
  lastName: 'Jordan',
  status: 'GOAT',
  stats: {
    A: '',
    B: ''
  }
};

Answer №2

To address this issue, one potential solution is to initialize the object outside of the reactive() function:

import { defineComponent, reactive } from 'vue'

//...

export default defineComponent({
  setup() {
    const initProfile: Baseball | Basketball | Football = {
      firstName: 'Michael',
      lastName: 'Jordan',
      status: 'GOAT',
      stats: {
        A: '1',
        C: '2',
      }
    }

    const user = reactive(initProfile)

    console.log(user.stats.C) // ✅
  }
})

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

To retrieve the id value stored in the database, you can use the onclick JavaScript event within the input tag

I have a piece of code that's successfully working for one function, but I want to approach it differently this time. Here is the code I'd like to use as inspiration: <td> <a href="javascript:edit_id('<?php echo $row[0]; ?& ...

How come my date computed property does not update reactively when changes occur?

I have a Date object in my data, and I need to convert the date into a string for a date picker component in Vuetify. The initial date is being read and displayed correctly. I am able to set the date as well - when I set a code breakpoint, I can see the ...

The error message "Uncaught TypeError: Unable to retrieve the 'length' property of an undefined object in Titanium" has occurred

Here is the data I am working with: {"todo":[{"todo":"Khaleeq Raza"},{"todo":"Ateeq Raza"}]} This is my current code snippet: var dataArray = []; var client = new XMLHttpRequest(); client.open("GET", "http://192.168.10.109/read_todo_list.php", true); c ...

Error encountered when attempting to send a jQuery Post to API due to Access-Control-Allow-Origin issue

I've been researching the 'Access-Control-Allow-Origin' error extensively, but I am still struggling to understand what needs to be fixed. Here's the code snippet in question: $.ajax({ url: 'http://54.149.190.45:8000/image/upl ...

Creating a query string in MongoDB using [Object] as a field

Currently, I am in the process of constructing a string within Meteor to delve deeper into my MongoDB data. The structure of my data can be seen here: Data In my JavaScript code for Meteor projects, I have formulated the string as shown below: const co ...

What could be causing my Bootstrap 4 Carousel to not appear on my site?

I followed all the steps to include the Bootstrap 4 carousel code correctly, including adding the necessary libraries and plugins at the end. While the navbar is functioning properly, I am puzzled as to why the carousel is not displaying. Is there somethin ...

How to Delete an Added Image from a Dialog Title in jQuery

I've tried multiple solutions from various sources, but I'm still struggling to remove an image from a dialog. Whenever I attempt to do so, I end up with multiple images instead of just one. It's important to note that I only want the image ...

Utilizing VueJS with a non-sequential JSON endpoint

Currently working on a VueJS project, I have a collection of JSON objects accessible through a .json endpoint. They are referred to as People, and by using VueResource, I am able to retrieve an array of people stored in this.people. While I can loop thro ...

Tips for effectively passing generics to React Hooks useReducer

I am currently working with React Hooks useReducer in conjunction with Typescript. I am trying to figure out how to pass a type to the Reducer Function using generics. interface ActionTypes { FETCH, } interface TestPayload<T> { list: T[]; } inter ...

The data type 'void' cannot be assigned to type '(event: MouseEvent<HTMLDivElement, MouseEvent>) => void'

Can you assist me in understanding what has occurred and provide guidance on the necessary steps to resolve it? I am currently working on a website where I am in need of hooks to update the state. The issue seems to be related to the onClick events within ...

Making changes to a variable within a Service

Hey there! I've been stuck on this code all day and could really use some help. I have a simple textbox that interacts with a controller to update a variable inside a service (which will eventually handle data from elsewhere). Currently, I can retri ...

What is the best method for implementing a Twitch <script> tag within Vue.js?

In an effort to replicate the functionality I achieved in Angular here, I am now attempting to do so within Vue.JS (2.6+). My goal is to utilize the Twitch API for embedding a Stream, which currently only offers usage through inline HTML: <script src= ...

What steps can I take to deactivate input and stop it from being accessible on the browser?

insert image description Is there a method to block users from accessing disabled input fields in the browser? Any recommendations or solutions would be greatly appreciated. Vuejs is utilized within my project. Implementing this feature serves as a secu ...

Utilizing Firebase authentication and next-auth in Next.js - Authentication currently returns null

I'm creating a website with nextjs 13 (app router) and incorporating firebase. I've come across suggestions to combine next-auth and firebase auth for using firebase auth effectively. Accordingly, I have configured my firebase Here is the fireba ...

Why does the details page consistently receive the final item from the list?

For my e-commerce project built with React, I have a section to showcase featured items. Currently, there are only 9 items marked as featured in my database. Additionally, I am working on a modal details popup page that appears when you click on any item. ...

Error TS2307: Module './images/logo.png' could not be located

I encountered an issue while attempting to import a local png image into my ts webpack project. The error message displayed was as follows: TS2307: Cannot find module './images/logo.png'. All other modules, such as css, svg, and ts files, impor ...

What is the process for incorporating TypeScript types into a JavaScript library?

After adding p5 and @types/p5 to my project, I imported p5 in the following way: import * as p5 from 'p5' However, when I tried using p5.createImage(100, 100), I encountered this error message indicating that 'createImage' is not a re ...

Tips for monitoring password and password confirmation fields in DevTools when using AngularJS forms

Within the ng-model, I have identified two variables: vm.user.password and vm.confirmpassword. The input fields are equipped with attributes such as id, name, and class. I am interested in monitoring both the password and confirmpassword values within Dev ...

A method for cycling through parent and child objects in JavaScript (Vue.js) and storing them in an array - how to

I have a JSON object structured like this. const jsonData = { "id": "6", "name": "parent", "path": "/", "category": "folder", "fid": "6", "children": [ { ...

Alter the font color once the page has finished loading

Is there a way to change the color of the "View Results" text below? <script type="text/javascript" charset="utf-8" src="http://static.polldaddy.com/p/6352993.js"></script> <noscript><a href="http://polldaddy.com/poll/6352993/"> ...