jackdaw
jackdaw

Reputation: 2314

Assign a different type based on a ternary statement in TypeScript

I have the following type:

selection: (InterfaceX | InterfaceY)[]

interface InterfaceX {
  switch: boolean
  propertyOne: number
}

interface InterfaceY {
  switch: boolean
  propertyTwo: number
}

Selection can be:

{switch: true, propertyOne: 1} or {switch: false, propertyTwo: 2}

Which causes the following type errors in a ternary:

selection.switch ? selection.propertyOne : selection.propertyTwo

TS2339: Property 'propertyOne' does not exist on type 'InterfaceY'.

As well as

TS2339: Property 'propertyTwo' does not exist on type 'InterfaceX'.

Is there a way to declare which side of the ternary is using which type? So if switch is true it is InterfaceX otherwise its InterfaceY? I do not want to add any properties to my interfaces. Thanks!

New example:

import React from "react";

export interface Props {
  items: (InterfaceX | InterfaceY)[];
}

interface InterfaceX {
  toggle: true;
  sharedProp: string;
  propertyX: string;
}

interface InterfaceY {
  toggle: false;
  sharedProp: string;
  propertyY: string;
}

export const Picks = (props: Props) => {
  const { items } = props;
  return items.map(item =>
    item.toggle ? (
      <div>
        {item.sharedProp} {item.propertyX} // Unresolved variable propertyX
      </div>
    ) : (
      <div>
        {item.sharedProp} {item.propertyY} // Unresolved variable propertyY
      </div>
    )
  );
};

Upvotes: 0

Views: 1471

Answers (1)

skovy
skovy

Reputation: 5650

Based on your example you'll want the switch property to be the exact value (not boolean) so that TypeScript can properly discriminate between the two types. Otherwise, since they can both be false and true there's no way to determine which type it is.

For example:

interface InterfaceX {
  switch: true;
  propertyOne: number;
}

interface InterfaceY {
  switch: false;
  propertyTwo: number;
}

// Example of using a ternary
const fn1 = (selection: InterfaceX | InterfaceY) => {
  selection.switch ? selection.propertyOne : selection.propertyTwo
}

// Example of using a swtich
const fn2 = (selection: InterfaceX | InterfaceY) => {
  switch (selection.switch) {
    case true:
      return selection.propertyOne;
    case false:
      return selection.propertyTwo
  }
}

TypeScript Playground

Upvotes: 2

Related Questions