[FIXED] How to infer names declared in a sibling array property?

Issue

I’m defining two different groups: Tabs and Sections. A section exists inside tabs.(Tabs contain sections).

When declaring sections, I’d like to have the tab names to be automatically filled by the sibling tabs that were just declared.

But how to infer the names of siblings? Here’s what I tried (Try it on playground):

export type TabDeclaration<TabName extends string = string> = {
  name?: TabName;
};

export type SectionDeclaration<
  Tabs extends TabDeclaration[],
  SectionName extends string = string
> = Tabs extends TabDeclaration<infer TabName>[]
  ? {
      name?: SectionName;
      tab?: TabName;
    }
  : never;

type TabsAndSections<Tabs extends TabDeclaration[] = TabDeclaration[]> = {
  tabs: Tabs;
  sections: SectionDeclaration<Tabs>[];
};

var tabsAndSections: TabsAndSections = {
  tabs: [
    {
      name: 'Tab 1'
    },
    {
      name: 'Tab 2'
    }
  ],
  sections: [
    {
      name: 'Section 1',
      tab: '' /* <---- Should autocomplete "Tab 1" or "Tab 2" */
    }
  ]
}

tab: should autocomplete "Tab 1" or "Tab 2".

Solution

You can create an identity helper function that infers the valid tab names from the passed in values.

The second type parameter L is constrained to K so the tab names in the sections can only be taken from the tabs

Playground

type Section<K extends string> = {
  name?: string;
  tab?: K;
}

type Tab<K extends string> = {
  name: K;
};

type TabsAndSections<K extends string, L extends K> = {
  tabs: Array<Tab<K>>,
  sections: Array<Section<L>>;
};

const asTabsAndSections = <K extends string, L extends K>(
  obj: TabsAndSections<K, L>
): TabsAndSections<K, L> => obj;

const tabsAndSections = asTabsAndSections({
  tabs: [
    {
      name: 'Tab 1'
    },
    {
      name: 'Tab 2'
    }
  ],
  sections: [
    {
      name: 'Section 1',
      tab: 'Tab 1' /* <---- Should autocomplete "Tab 1" or "Tab 2" */
    }
  ]
})

Answered By – Iain Shelvington

Answer Checked By – Marie Seifert (Easybugfix Admin)

Leave a Reply

(*) Required, Your email will not be published