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
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<T> = T extends ViewerTypes ? PreviewTypes[T] : false;
//attempt #2
type ViewerMaybe<T> = T extends keyof PreviewTypes ? PreviewTypes[T] : false
export function getViewer<K extends ViewerTypes>(filename: K): ViewerMaybe<typeof filename> {
const type = (filename.split('.').pop()?.toLowerCase() as ViewerTypes) || 'unknown';
const viewer = Object.prototype.hasOwnProperty.call(previewTypes, type) === true
? previewTypes[type]
: false;
return viewer;
}
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.
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 indexed access type that says something like
type ViewerIndexMap<T> = {
[Prop in keyof T]: Prop in keyof T ? T[Prop] : false
}
and then,
export function getViewer(filename): ViewerIndexMap<typeof filename>
or something like that
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.
Thank you!