Skip to content Skip to sidebar Skip to footer

Defining A Choice Of Index Type On An Interface

Lets say i have an interface Animal, and i want it to have some general properties, and then either be a cat or a dog and have corresponding properties. interface Dog { dog: {

Solution 1:

Unions like Cat | Dog are inclusive, meaning that something is a Cat | Dog if it is a Cat or a Dog or both. TypeScript doesn't have a general exclusive union operator. If your unions share a common property with distinct values, you can use discriminated unions like @MateuszKocz suggests. Otherwise, you could build your ownXor type function for objects:

type ProhibitKeys<K extends keyof any> = { [PinK]?: never }

type Xor<T, U> = (T & ProhibitKeys<Exclude<keyof U, keyof T>>) |
  (U & ProhibitKeys<Exclude<keyof T, keyof U>>);

Then you can define Animal as the exclusive union of Cat and Dog, intersected with the additional properties common to all Animals:

typeAnimal = Xor<Cat, Dog> & { weight: number };

Now you can get your desired behavior (type annotations are superior to type assertions so I am using those here):

// Success
const dog: Animal = {
  weight: 5,
  dog: { sound: "woof" }
}

// Error, {lives: number} not assignable to undefined
const errorAnimal: Animal = {
  weight: 5,
  dog: { sound: "woof" },
  cat: { lives: 9 }
}

Hope that helps; good luck!

Solution 2:

If you are willing to change your code a bit, then tagged unions will be the answer you're looking for.

interface CommonAnimal {
  weight: number
}

interface Dog extends CommonAnimal {
  // This is the important part. `type` a tag used by TS to recognise this type.type: 'dog'
  sound: string
}

interface Cat extends CommonAnimal {
  type: 'cat'
  lives: number
}

type Animal = Dog | Cat

const dog: Animal = {
  type: 'dog',
  weight: 10,
  sound: 'woof'
}

const cat: Animal = {
  type: 'cat',
  weight: 5,
  lives: 9
}

const robot: Animal = {
  type: 'robot'// error
}

That way you'll be able to keep values on one level, without nesting, while satisfying TS's type recognition.

Post a Comment for "Defining A Choice Of Index Type On An Interface"