The aim of this code is simply to show related fields in data
field dependent on eventType
.
When ChangePassword
is selected in eventType
filed, then userName
, oldPassword
and newPassword
are becoming as required fields.
When ForgotPassword
is selected in eventType
field, then userName
is just becoming required.
const msg1 = publishMessage?.({
eventType: 'ChangePassword',
data: {
userName: '',
oldPassword: '',
newPassword: '',
},
subject: '',
topic: '',
});
const msg2 = publishMessage?.({
eventType: 'ChangePassword_Success',
data: {
emailSubject: 'Password Verification code is ######',
emailMessage: '',
},
subject: '',
topic: '',
});
const msg3 = publishMessage?.({
eventType: 'ForgotPassword',
data: {
userName: ''
},
subject: '',
topic: '',
});
const msg4 = publishMessage?.({
eventType: 'ForgotPassword_Success',
data: {
resetPasswordVerificationCode: '',
emailSubject: '',
emailMessage: ''
},
subject: '',
topic: '',
});
Example 1
type BaseEventData = {
appName: string;
appVersion: string;
correlationId: string;
operationId: string;
businessId: string;
};
type EventSuccess = Partial<BaseEventData> & {
emailSubject: string;
emailMessage: string;
}
type EventError = Partial<BaseEventData> & {
message: string;
};
type SignUp = Partial<BaseEventData> & {
userName: string;
hashedPassword: string;
};
type SignUp_Success = Pick<EventSuccess, keyof EventSuccess> & {
registrationVerificationCode: string;
};
type SignUp_Failure = Pick<EventError, keyof EventError>;
type ForgotPassword = Partial<BaseEventData> & {
userName: string;
};
type ForgotPassword_Success = Pick<EventSuccess, keyof EventSuccess> & {
resetPasswordVerificationCode: string;
};
type ForgotPassword_Failure = Pick<EventError, keyof EventError>;
type ChangePassword = Partial<BaseEventData> & {
userName: string;
oldPassword: string;
newPassword: string;
};
type ChangePassword_Success = Pick<EventSuccess, keyof EventSuccess>;
type ChangePassword_Failure = Pick<EventError, keyof EventError>;
type ResetPassword = Partial<BaseEventData> & {
userName: string;
newPassword: string;
resetPasswordVerificationCode: string;
};
type ResetPassword_Success = Pick<EventSuccess, keyof EventSuccess>;
type ResetPassword_Failure = Pick<EventError, keyof EventError>;
type ResendConfirmationCode = Partial<BaseEventData> & {
userName: string;
};
type ResendConfirmationCode_Success = Pick<EventSuccess, keyof EventSuccess>;
type ResendConfirmationCode_Failure = Pick<EventError, keyof EventError>;
type EventTypes = {
SignUp: SignUp;
SignUp_Success: SignUp_Success;
SignUp_Failure: SignUp_Failure;
ChangePassword: ChangePassword;
ChangePassword_Success: ChangePassword_Success;
ChangePassword_Failure: ChangePassword_Failure;
ForgotPassword: ForgotPassword;
ForgotPassword_Success: ForgotPassword_Success;
ForgotPassword_Failure: ForgotPassword_Failure;
ResetPassword: ResetPassword;
ResetPassword_Success: ResetPassword_Success;
ResetPassword_Failure: ResetPassword_Failure;
ResendConfirmationCode: ResendConfirmationCode;
ResendConfirmationCode_Success: ResendConfirmationCode_Success;
ResendConfirmationCode_Failure: ResendConfirmationCode_Failure;
};
type EventTypeNames = keyof EventTypes;
interface EventGridMessage<TEventType extends EventTypeNames = EventTypeNames> {
id: string;
topic: string;
subject: string;
eventTime: string;
eventType: TEventType;
data: EventTypes[TEventType];
dataVersion: string;
metadataVersion: string;
}
type EventGridMessageRequiredParams<TEventType extends EventTypeNames = EventTypeNames> = Pick<EventGridMessage<TEventType>, 'data' | 'eventType' | 'subject' | 'topic'>;
type ExistingMessageBuilder<TEventType extends EventTypeNames = EventTypeNames> = (parameters: EventGridMessageRequiredParams<TEventType>) => EventGridMessageRequiredParams<TEventType>;
type PublishMessageType =
(
& (<TEventType extends EventTypeNames>(parameters: EventGridMessageRequiredParams<TEventType>) => EventGridMessage<TEventType> | undefined)
& (<TEventType extends EventTypeNames>(eventType: TEventType, parameters: EventGridMessageRequiredParams<TEventType> | ExistingMessageBuilder<TEventType>) => EventGridMessage<TEventType> | undefined)
) |
undefined;
type EventGridMessageParamsUnion<TEventType extends EventTypeNames = EventTypeNames> = EventGridMessageRequiredParams<TEventType> | ExistingMessageBuilder<TEventType>;
const createEventGridMessage = <TEventType extends EventTypeNames>({ eventType, data, topic, subject }: EventGridMessageRequiredParams<TEventType>): EventGridMessage<TEventType> => ({
id: '',
topic,
subject,
eventType,
eventTime: new Date().toString(),
data,
dataVersion: '1.0',
metadataVersion: '1.0',
});
const isEventGridMessageRequiredParams = (obj: any): obj is EventGridMessageRequiredParams => {
if (typeof obj !== 'function') {
const fields = ['data', 'eventType', 'subject', 'topic'];
return Object.keys(obj).every(item => fields.some(i => i === item));
}
return false;
};
const publishMessage = <TEventType extends EventTypeNames>(eventGridMessages: Array<EventGridMessage>, parameters: EventGridMessageRequiredParams<TEventType>, baseEventData: BaseEventData): EventGridMessage<TEventType> => {
parameters.data = { ...baseEventData, ...(parameters.data) };
const newEventGridMessage = createEventGridMessage<TEventType>(parameters);
const existingEventGridMessage = eventGridMessages.find(item => item.eventType === parameters.eventType);
if (existingEventGridMessage) {
Object.assign(existingEventGridMessage, newEventGridMessage);
} else {
eventGridMessages.push(newEventGridMessage);
}
return newEventGridMessage;
}
const getPublishMessageFunction = (eventGridMessages: Array<EventGridMessage>, baseEventData: BaseEventData): PublishMessageType =>
<TEventType extends EventTypeNames>(...args: any[]) => {
const [arg1, arg2] = args;
const eventType: EventTypeNames = arg2 && arg1;
const parameters: EventGridMessageParamsUnion<TEventType> = arg2 || arg1;
let eventMessage: EventGridMessage<TEventType> | undefined;
if (isEventGridMessageRequiredParams(parameters)) {
eventMessage = publishMessage<TEventType>(eventGridMessages, parameters, baseEventData);
}
else {
const existingEventGridMessage = eventGridMessages.find(item => item.eventType === eventType);
if (existingEventGridMessage) {
const newParameters = parameters(existingEventGridMessage as EventGridMessage<TEventType>);
eventMessage = publishMessage(eventGridMessages, newParameters, baseEventData);
}
}
return eventMessage;
};
const main = () => {
const eventGridMessages: Array<EventGridMessage> = [];
const baseEventData: BaseEventData = {
appName: '',
appVersion: '1.0',
businessId: '111',
correlationId: '111',
operationId: '111',
};
const publishMessage = getPublishMessageFunction(eventGridMessages, baseEventData);
const msg1 = publishMessage?.({
eventType: 'ChangePassword',
data: {
userName: '',
oldPassword: '',
newPassword: ''
},
subject: '',
topic: '',
});
const msg2 = publishMessage?.({
eventType: 'ChangePassword_Success',
data: {
emailSubject: 'Password Verification code is ######',
emailMessage: ''
},
subject: '',
topic: '',
});
};
Example 1 – Updated
Notice that I didn't use default values in Generic Types.
type BaseEventData = {
appName: string;
appVersion: string;
correlationId: string;
operationId: string;
businessId: string;
};
type EventSuccess = Partial<BaseEventData> & {
emailSubject: string;
emailMessage: string;
}
type EventError = Partial<BaseEventData> & {
message: string;
};
type SignUp = Partial<BaseEventData> & {
userName: string;
hashedPassword: string;
};
type SignUp_Success = Pick<EventSuccess, keyof EventSuccess> & {
registrationVerificationCode: string;
};
type SignUp_Failure = Pick<EventError, keyof EventError>;
type ForgotPassword = Partial<BaseEventData> & {
userName: string;
};
type ForgotPassword_Success = Pick<EventSuccess, keyof EventSuccess> & {
resetPasswordVerificationCode: string;
};
type ForgotPassword_Failure = Pick<EventError, keyof EventError>;
type ChangePassword = Partial<BaseEventData> & {
userName: string;
oldPassword: string;
newPassword: string;
};
type ChangePassword_Success = Pick<EventSuccess, keyof EventSuccess>;
type ChangePassword_Failure = Pick<EventError, keyof EventError>;
type ResetPassword = Partial<BaseEventData> & {
userName: string;
newPassword: string;
resetPasswordVerificationCode: string;
};
type ResetPassword_Success = Pick<EventSuccess, keyof EventSuccess>;
type ResetPassword_Failure = Pick<EventError, keyof EventError>;
type ResendConfirmationCode = Partial<BaseEventData> & {
userName: string;
};
type ResendConfirmationCode_Success = Pick<EventSuccess, keyof EventSuccess>;
type ResendConfirmationCode_Failure = Pick<EventError, keyof EventError>;
type EventTypes = {
SignUp: SignUp;
SignUp_Success: SignUp_Success;
SignUp_Failure: SignUp_Failure;
ForgotPassword: ForgotPassword;
ForgotPassword_Success: ForgotPassword_Success;
ForgotPassword_Failure: ForgotPassword_Failure;
ChangePassword: ChangePassword;
ChangePassword_Success: ChangePassword_Success;
ChangePassword_Failure: ChangePassword_Failure;
ResetPassword: ResetPassword;
ResetPassword_Success: ResetPassword_Success;
ResetPassword_Failure: ResetPassword_Failure;
ResendConfirmationCode: ResendConfirmationCode;
ResendConfirmationCode_Success: ResendConfirmationCode_Success;
ResendConfirmationCode_Failure: ResendConfirmationCode_Failure
};
type EventTypeNames = keyof EventTypes;
type EventGridMessage<TEventType extends EventTypeNames> = {
id: string;
topic: string;
subject: string;
eventTime: string;
eventType: Extract<TEventType, TEventType>;
data: EventTypes[TEventType];
dataVersion: string;
metadataVersion: string;
};
type EventGridMessageRequiredFields<TEventType extends EventTypeNames> = Pick<EventGridMessage<TEventType>, 'eventType' | 'data' | 'subject' | 'topic'>;
type EventGridMessageExistingFields<TEventType extends EventTypeNames> = (parameters: EventGridMessageRequiredFields<TEventType>) => EventGridMessageRequiredFields<TEventType>;
type EventGridMessageFieldsUnion<TEventType extends EventTypeNames> = EventGridMessageRequiredFields<TEventType> | EventGridMessageExistingFields<TEventType>;
type PublishMessageType =
(
& (<TEventType extends EventTypeNames>(parameters: EventGridMessageRequiredFields<TEventType>) => EventGridMessage<TEventType> | undefined)
& (<TEventType extends EventTypeNames>(eventType: TEventType, parameters: EventGridMessageExistingFields<TEventType>) => EventGridMessage<TEventType> | undefined)
) |
undefined;
const createEventGridMessage = <TEventType extends EventTypeNames>({ eventType, data, subject, topic }: EventGridMessageRequiredFields<TEventType>): EventGridMessage<TEventType> => ({
id: '',
topic,
subject,
eventType,
eventTime: new Date().toString(),
data,
dataVersion: '1.0',
metadataVersion: '1.0',
});
const isEventGridMessageRequiredFields = (obj: any): obj is EventGridMessageRequiredFields<any> => {
if (typeof obj !== 'function') {
const fields = ['data', 'eventType', 'subject', 'topic'];
return Object.keys(obj).every(item => fields.some(i => i === item));
}
return false;
};
const publishMessage = <TEventType extends EventTypeNames>(eventGridMessages: Array<EventGridMessage<TEventType>>, parameters: EventGridMessageRequiredFields<TEventType>, baseEventData: BaseEventData): EventGridMessage<TEventType> => {
parameters.data = { ...baseEventData, ...(parameters.data) };
const newEventGridMessage = createEventGridMessage<TEventType>(parameters);
const existingEventGridMessage = eventGridMessages.find(item => item.eventType === parameters.eventType);
if (existingEventGridMessage) {
Object.assign(existingEventGridMessage, newEventGridMessage);
} else {
eventGridMessages.push(newEventGridMessage);
}
return newEventGridMessage;
};
const getPublishMessageFunction = (eventGridMessages: Array<EventGridMessage<any>>, baseEventData: BaseEventData): PublishMessageType =>
<TEventType extends EventTypeNames>(...args: any[]) => {
const [arg1, arg2] = args;
const eventType: EventTypeNames = arg2 && arg1;
const parameters: EventGridMessageFieldsUnion<TEventType> = arg2 || arg1;
let eventMessage: EventGridMessage<TEventType> | undefined;
if (isEventGridMessageRequiredFields(parameters)) {
eventMessage = publishMessage<TEventType>(eventGridMessages, parameters, baseEventData);
}
else {
const existingEventGridMessage = eventGridMessages.find(item => item.eventType === eventType);
if (existingEventGridMessage) {
const newParameters = parameters(existingEventGridMessage as EventGridMessage<TEventType>);
eventMessage = publishMessage(eventGridMessages, newParameters, baseEventData);
}
}
return eventMessage;
};
const main = () => {
const eventGridMessages: Array<EventGridMessage<any>> = [];
const baseEventData: BaseEventData = {
appName: '',
appVersion: '1.0',
businessId: '111',
correlationId: '111',
operationId: '111',
};
const publishMessage = getPublishMessageFunction(eventGridMessages, baseEventData);
const msg1 = publishMessage?.({
eventType: 'ChangePassword',
data: {
userName: '',
oldPassword: '',
newPassword: '',
},
subject: '',
topic: '',
});
const msg2 = publishMessage?.({
eventType: 'ChangePassword_Success',
data: {
emailSubject: 'Password Verification code is ######',
emailMessage: '',
},
subject: '',
topic: '',
});
const msg3 = publishMessage?.({
eventType: 'ForgotPassword',
data: {
userName: ''
},
subject: '',
topic: '',
});
const msg4 = publishMessage?.({
eventType: 'ForgotPassword_Success',
data: {
resetPasswordVerificationCode: '',
emailSubject: '',
emailMessage: ''
},
subject: '',
topic: '',
});
};