title: How can I write a react component that has dependent props in TypeScript?
body: <p>How can I write Typescript types for a React component where the value of one of the props depends on the value of another prop?</p>
  <p>I am trying to write an <code>Icon</code> component that looks up the SVG path for an icon from a pre-defined map.  The map is nested such that the top-level properties are the icon styles.  Each of those styles has its own map where the properties are the icon names.  Like this:</p>
  <pre><code>const icons = {
    regular: {
      check: '',
    },
    solid: {
      on: '',
    },
  };
  </code></pre>
  <p>The component takes a prop <code>$flair</code> which is the icon style and <code>$name</code> which is the icon name.  I need these two props to be related such that the values of <code>$name</code> are limited to the icons of this <code>$flair</code>.  If <code>$flair</code> is <code>'regular'</code> then <code>$name</code> can be <code>'check'</code> but it cannot be <code>'on'</code>.</p>
  <p>Here is what I have to so far:</p>
  <pre><code>type Icons = typeof icons;
  type FlairNames = keyof Icons;
  type IconNames = keyof Icons['regular'] | keyof Icons['solid'];
  
  type Test = Extract&lt;IconNames, keyof Icons['regular']&gt;;
  
  interface IconProps&lt;F extends FlairNames&gt; {
    $size?: number;
    $flair: F;
    $name: Extract&lt;IconNames, keyof Icons[F]&gt;;
  }
  
  function IconImpl({
    $size,
    $flair,
    $name,
  }: IconProps&lt;'regular'&gt; | IconProps&lt;'solid'&gt;): JSX.Element {
    const flair = icons[$flair];
    const d = flair[$name];
  
    return (
      &lt;svg&gt;
        &lt;path d={d} /&gt;
      &lt;/svg&gt;
    );
  }
  </code></pre>
  <p><a href="https://www.typescriptlang.org/play?ssl=1&amp;ssc=1&amp;pln=2&amp;pc=1#code/MYewdgzgLgBAlqSMC8MDeAoGMBOBTAcwFcAbAQxwC50tsZgALPYAa2oHJ2AaWgXx%20wQQJOABNqmOjHAdufHrwDcGDFACeABzwwAkoggoY6rSABm8fcuPaAYuTg4AcmQC2eA6hZ41Z3ZdWa2nrgzm4eMF4%205sGQANrs%20MTkOOwAujAAPhHevjEQ8UIiomnKAVowACrusKgAogAeUDhkwFAAPDGh7lzZUX7g%20QmEpBRpAHylcGBQeDimLUGIAAo4IBoQbTYweI14YKIGdmQOXRBjNNgAJBBwAF54APzUYEQuAEazylem9lQwNl8YJcwK48NQGk0Wu1OqCID1Irl9LEbKkJhheCpTEQwK04OB%20mAdC4NCQABSSIE3e4CIE-Y44GnA0EKagxFZrDZDJKjc5ZNmrdZtdiFMTsMYASmoACkAMoADQAdLUSHg3NMLvQBrA6Q5DAgBrFLjqcKlAfpYKJDMbDSC3KaVNh8FAiDgwDBSbRsG0IAA3AhjT10NoaMhQBgwUTINCiXgwAD0AakbTjvv9tHFygxQA" rel="nofollow noreferrer">Typescript Playground Link</a></p>
  <p>I'd like to be able to use the component as follows:</p>
  <pre><code>&lt;Icon $flair=&quot;regular&quot; $name=&quot;check&quot; /&gt;
  &lt;Icon $flair=&quot;solid&quot; $name=&quot;on&quot; /&gt;
  &lt;Icon $flair=&quot;regular&quot; $name=&quot;does-not-exist&quot; /&gt; // error
  &lt;Icon $flair=&quot;regular&quot; /&gt; // error
  &lt;Icon $name=&quot;on&quot; /&gt; // error
  </code></pre>