Lin Du
Lin Du

Reputation: 102257

How to infer type correctly based on another type?

I want to infer the type of tab object to {leftText: string, rightText?: string} type when props.group is true, to {title: string} type when props.group is false.

type ButtonTab =
  | {
      leftText: string;
      rightText?: string;
    }
  | { title: string };

interface ButtonTabsProps {
  tabsList: ButtonTab[];
  group?: boolean;
}

function ButtonTabs(props: Readonly<ButtonTabsProps>) {
    return props.tabsList.map((tab: ButtonTab) => {
        if(props.group) {
            return `${tab.leftText} ${tab.rightText}`
        }
        return `${tab.title}`
    })
}

For now, TSC throw an error:

Property 'leftText' does not exist on type 'ButtonTab'. Property 'leftText' does not exist on type '{ title: string; }'.

code: TypeScript Playground

Upvotes: 0

Views: 101

Answers (2)

Denis Frezzato
Denis Frezzato

Reputation: 968

interface ButtonTabText {
  leftText: string
  rightText?: string
}
interface ButtonTabTitle {
  title: string
}

interface ButtonTabsText {
  group: true
  tabsList: ButtonTabText[]
}
interface ButtonTabsTitle {
  group: false
  tabsList: ButtonTabTitle[]
}

type Props = ButtonTabsTitle | ButtonTabsText

const renderTabsText = (tabsList: ButtonTabText[]): string[] =>
  tabsList.map((tab) => `${tab.leftText} ${tab.rightText}`)

const renderTabsTitle = (tabsList: ButtonTabTitle[]): string[] =>
  tabsList.map((tab) => tab.title)

function ButtonTabs(props: Readonly<Props>) {
  return props.group
    ? renderTabsText(props.tabsList)
    : renderTabsTitle(props.tabsList)
}

Upvotes: 0

Nghiệp
Nghiệp

Reputation: 4718

In your code the props.group prop there are no related with ButtonTab type.

And props.group should be moving out.

type ButtonTab<G extends boolean = true> = G extends true
  ? {
      leftText: string;
      rightText?: string;
    }
  : {title: string};

type ButtonTabsProps =
  | {
      tabsList: ButtonTab<true>[];
      group: true;
    }
  | {
      tabsList: ButtonTab<false>[];
      group: false;
    };

function ButtonTabs(props: ButtonTabsProps) {
  if (props.group) {
    return props.tabsList.map(tab => {
      return `${tab.leftText} ${tab.rightText}`;
    });
  }

  return props.tabsList.map(tab => {
    return `${tab.title}`;
  });
}

TS Playground

Upvotes: 2

Related Questions