0

Given the following Typescript interfaces, how should I set user to accept interface Baseball, Basketball, or Football, where properties vary?

Currently, the only properties accessible are those which overlap. In this example being user.stats.A.

I am working within 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
        }
    }
})

2 Answers 2

2

What you have is perfectly fine. In fact you did the right thing. You will always have to provide at least the properties of interface of the union type. I would suggest to do something like this

// I(nterface)User
type IUser = Baseball | Basketball | Football;

When you are unsure about what object your getting the only thing you can do is test for the properties you need.

Here is an explanation of a custom XOR type. Maybe this can help you. This will not allow you to put A, B AND C but only the properties of a single 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: ''
  }
};

Sign up to request clarification or add additional context in comments.

2 Comments

Unfortunately, when attempting to access any property which is not mutually shared, I receive the Property 'X' does not exist on type ' Vetur(2339) error.
Sure I hope it helps. I can just recommend you to have a closer look to the other thread I linked. Im sorry to say that if this is an vue related issue I can't really help you out with that.
1

A workaround is to move the object initialization outside of the reactive():

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) // ✅
  }
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.