title: How do I correctly type a function that checks whether a key exists in object, and returns the corresponding value?
body: <p>I held off a long while thinking I would come across the answer, but I still haven't so I'm giving SO a shot</p>
  <pre><code>import { PDFViewer, MSViewer } from './viewerclasses'
  
  //tried adding in just a union of the keys
  type ViewerTypes = 'xls' | 'xlsx' | 'doc' | 'docx' | 'pdf';
  
  type PreviewTypes = {
      pdf: typeof PDFViewer;
      doc: typeof PDFViewer;
      docx: typeof PDFViewer;
      xls: typeof MSViewer;
      xlsx: typeof MSViewer;
  }
  
  
  const previewTypes: PreviewTypes = {
      pdf: PDFViewer,
      doc: PDFViewer,
      docx: PDFViewer,
      xls: MSViewer,
      xlsx: MSViewer
  };
  
  //attempt #1
  type ViewerMap&lt;T&gt; = T extends ViewerTypes ? PreviewTypes[T] : false;
  //attempt #2
  type ViewerMaybe&lt;T&gt; = T extends keyof PreviewTypes ? PreviewTypes[T] : false
  
  export function getViewer&lt;K extends ViewerTypes&gt;(filename: K): ViewerMaybe&lt;typeof filename&gt; {
  
      const type = (filename.split('.').pop()?.toLowerCase() as ViewerTypes) || 'unknown';
  
      const viewer = Object.prototype.hasOwnProperty.call(previewTypes, type) === true
      ? previewTypes[type]
      : false;
  
      return viewer;
  }
  </code></pre>
  <p>But I'm just shooting in the dark here, trying to give getViewer() different types, mapped types, indexed access types, etc, etc, but TS still doesn't really know what I'm trying to do.</p>
  <p>I'm trying to type getViewer() correctly, so that Typescript knows if I hand in a key of previewTypes as an argument, I get a constructor back, and if not, I get false back. I've brushed over this problem for so long, but I would like to understand the type system enough to tackle it. I know there's a way to create an <strong>indexed access type</strong> that says something like</p>
  <pre><code>type ViewerIndexMap&lt;T&gt; = {
  [Prop in keyof T]: Prop in keyof T ? T[Prop] : false 
  }
  </code></pre>
  <p>and then,</p>
  <pre><code>export function getViewer(filename): ViewerIndexMap&lt;typeof filename&gt;
  </code></pre>
  <p>or <strong>something</strong> like that</p>
  <p>Where am I going wrong? What am I missing? I just re-read the TS handbook, and while I feel like mapped types are close, they don't get me exactly where I need to be.</p>
  <p>Thank you!</p>