I was told to post my question here from a comment on my question at Stack Overflow..
With reference to my code below, I am trying to create a Map<string, Function> (eventHandlerMap
in the code below) such that each of its keys is a string from (PortalEvent
in the code below) Union type. The value of each property should be a function that must return an object of specific type (in this example one of UserComment
or Author
).
Objectives:
If a new key is added to
PortalEvent
(without any other change in code), a compile time failure should enforce a handler function to be defined for that new key andeventHandlerMap
should be updated.If
Author
orUserComment
type is changed the above, a compile time failure should enforce changing the structure of returned object in the respective handler.
If it helps the types PortalEvent
, UserComment
and Author
are 3rd-party library maintained types and I want to be able to update my code whenever a new version of 3rd-party library is used in the project.
Here is the code I have come up: Playground Link
// Typescript Version 5.1.6
// Code for which I have no control over
// -------------------------------------
type PortalEvent = 'comment_created' | 'author_updated';
type UserComment = {
id: string;
content: string;
}
type Author = {
id: string;
name: string;
country: string
}
// Code that I can change
// ----------------------
// Define the types necessary for defining object eventHandlerMap
type HandlerReturnType = {
'comment_created': UserComment,
'author_updated': Author,
}
type HandlerArgType = {
'comment_created': { arg1: number, arg2: string; },
'author_updated': { arg1: string },
}
type THandlerMap<A extends {[j in PortalEvent]: unknown}, R extends {[j in PortalEvent]: unknown}> = {
[key in PortalEvent]: (arg: A[key]) => R[key] ;
};
// Define the Event handler map
const eventHandlerMap: THandlerMap<HandlerArgType, HandlerReturnType> = {
'comment_created': commentCreatedHandler,
'author_updated': authorUpdatedHandler,
}
function commentCreatedHandler(args: HandlerArgType['comment_created']): UserComment {
let id: string = '', content: string = '';
// ... code to initialize id and content properties
return {
id,
content,
};
}
function authorUpdatedHandler(args: HandlerArgType['author_updated']): Author {
let id: string = '', name: string = '', country : string = '';
// ... code to initialize id, name and country properties
return {
id,
name,
country
};
}
The code above achieves the listed objectives. Is there a better way of doing this?