Reputation: 43
I`m trying to define function with 2 args: (templateKey: T, templateData: ObjectType) => ... where templateKey is a well known mapped value and templateData is data specified for this key. As result i want one function to work with all templates from one place.
I've tried this:
export const Template = [
'CASE1',
'CASE2',
] as const;
type RequestDTO = {
test: string,
}
type RequestDTO2 = {
jest: string,
}
type ObjectType<T extends TemplateKey> =
T extends 'CASE1' ? RequestDTO :
T extends 'CASE2' ? RequestDTO2 :
never;
export type TemplateKey = typeof Template[number];
const func = async <T extends TemplateKey>({ template, templateData } : { template: T, templateData: ObjectType<T> }) => 1;
const U = func({ template: 'CASE1', templateData: { test: '123' } });
All works fine for me - hints are where they must be and this way pretty convenient. But! I see one awkward thing: no typehints when i write new rule in T extends 'CASE2' ? RequestDTO2
and when number of templates grows, there will be huge ObjectType
ruleset with rows of ternary operators without typehitting... But i have no idea how to do it without a map or something like map and im a bit confused.
Have you any ideas about how to optimize this or what i did wrong?
Upvotes: 1
Views: 1236
Reputation: 43
type TemplateDTO = {
baz: string,
}
type TemplateMeta<T> = {
bar: value;
} & T
type SomeEventMeta = {
foo: string,
}
enum Template = {
SOMEVENT = 'someEvent'
}
type TemplateDTO = {
[NotificationTemplate.SOMEVENT]: TemplateDTO;
}
type TemplateMetaMap = {
[NotificationTemplate.SOMEVENT]: TemplateMeta<SomeEventMeta>,
}
type TemplateType = keyof Record<Template, string>;
const create = (template: Template,
templateData: TemplateDTO[TemplateType],
meta: TemplateMetaMap[TemplateType]) => {...};
Relying on answers i did it. I wanted to avoid map-types and wanted to use generics, but it will require a lot of such code in project:
notify<typeHere, typeThere>(...)
and IMO what in my case is redundant and will make code more complicated and refactoring will take more time against case when 3 maps are placed in one file and all i need is to add new interface and pass it to TemplateMeta, and TemplateMeta contains common values for all templates, somewhere i need it, somewhere not, so its generic. And TemplateDTO hardly binded to Template cos w/o this data Template wont work at all. Thanks everyone, im gonna now try it out on my project.
Upvotes: 0
Reputation: 53185
You can simply build an interface to map your (Template) keys to their corresponding data type, then list available keys using keyof
and request the associated data type:
interface Template {
CASE1: RequestDTO;
CASE2: RequestDTO2;
}
function func<T extends keyof Template>({
template: T,
templateData: Template[T]
}) {}
func({
template: "CASE1",
templateData: {
test: ""
},
});
Upvotes: 1