Skip to content

Instantly share code, notes, and snippets.

@luisvinicius09
Last active March 1, 2024 21:29
Show Gist options
  • Save luisvinicius09/78677634941bb476c31e5f1427eda871 to your computer and use it in GitHub Desktop.
Save luisvinicius09/78677634941bb476c31e5f1427eda871 to your computer and use it in GitHub Desktop.
Event Processor challenge - NO BS TS
---- BASIC CHALLENGE ----
interface MyEvent<T> {
eventName: keyof T;
data: T[keyof T];
}
type MyFilterType<T, Key extends keyof T> = { eventName: Key; callback: (data: T[Key]) => boolean };
type MyMapType<T, Key extends keyof T> = { eventName: Key; callback: (data: T[Key]) => T[Key] };
abstract class EventProcessor<T> {
protected events: MyEvent<T>[] = [];
protected filters: MyFilterType<T, keyof T>[] = [];
protected maps: MyMapType<T, keyof T>[] = [];
abstract handleEvent(eventName: keyof T, data: T[keyof T]): void;
addFilter<Key extends keyof T>(eventName: Key, filter: MyFilterType<T, Key>['callback']): void {
this.filters.push({ eventName: eventName, callback: filter as (data: T[keyof T]) => boolean });
return;
}
addMap<Key extends keyof T>(eventName: Key, map: MyMapType<T, Key>['callback']): void {
this.maps.push({
eventName: eventName,
callback: map as unknown as (data: T[keyof T]) => T[keyof T],
});
return;
}
public getProcessedEvents(): MyEvent<T>[] {
return this.events;
}
}
interface EventMap {
login: { user?: string | null; name?: string; hasSession?: boolean };
logout: { user?: string };
}
class UserEventProcessor extends EventProcessor<EventMap> {
public handleEvent(eventName: keyof EventMap, data: EventMap[keyof EventMap]) {
let shouldProcess = true;
for (const item of this.filters) {
if (item.eventName === eventName) {
if (!item.callback(data)) {
shouldProcess = false;
break;
}
}
}
if (shouldProcess) {
let mappedData = { ...data };
this.maps.forEach((item) => {
if (item.eventName === eventName) {
mappedData = item.callback(data);
}
});
this.events.push({ eventName: eventName, data: mappedData });
}
return;
}
}
const uep = new UserEventProcessor();
uep.addFilter('login', ({ user }) => Boolean(user));
uep.addMap('login', (data) => ({
...data,
hasSession: Boolean(data.user && data.name),
}));
uep.handleEvent('login', {
user: null,
name: 'jack',
});
uep.handleEvent('login', {
user: 'tom',
name: 'tomas',
});
uep.handleEvent('logout', {
user: 'tom',
});
console.log(uep.getProcessedEvents());
/*
Result:
[
{
eventName: 'login',
data: { user: 'tom', name: 'tomas', hasSession: true }
},
{ eventName: 'logout', data: { user: 'tom' } }
]
*/
---- ADVANCED CHALLENGE ----
type Handlers = "filter" | "map";
type HandlerFunctionName<T> = `${Handlers}${Capitalize<Extract<keyof T, string>>}`; // that extract weirdly sucks
// type HandlerFunctionName<T> = `${Handlers}${Capitalize<keyof T & string>}`; // that extract weirdly sucks
// https://stackoverflow.com/questions/72264448/template-literal-from-keyof-in-class
// TODO: fix that extract or make sure it's okay
type MyEventType<T, Key extends keyof T> = { eventName: Key, data: T[Key] };
type MyHandlerType<T, Key extends keyof T> = { [Property in HandlerFunctionName<T>]: (data: T[Key]) => T[Key] };
class EventProcessor<T extends object> {
private events: MyEventType<T, keyof T>[] = [];
private handlers: MyHandlerType<T, keyof T>[] = [];
handleEvent<Key extends keyof T>(eventName: Key, data: T[Key]): void {
// tODO run events
let shouldProcess: true;
}
addHandler(handler: MyHandlerType<T, keyof T>): void {
// this.handlers = { ...this.handlers, handler }
this.handlers.push(handler);
return;
}
getProcessedEvents(): MyEventType<T, keyof T>[] {
return this.events;
}
}
interface EventMap {
login: { user?: string; name?: string; hasSession?: boolean };
logout: { user?: string };
}
class UserEventProcessor extends EventProcessor<EventMap> { }
const uep = new UserEventProcessor();
uep.addHandler({
filterLogin: ({ user }) => Boolean(user),
mapLogin: (data) => ({
...data,
hasSession: Boolean(data.user && data.name),
}),
});
uep.handleEvent("login", {
user: null,
name: "jack",
});
uep.handleEvent("login", {
user: "tom",
name: "tomas",
});
uep.handleEvent("logout", {
user: "tom",
});
console.log(uep.getProcessedEvents());
/*
Result:
[
{
eventName: 'login',
data: { user: 'tom', name: 'tomas', hasSession: true }
},
{ eventName: 'logout', data: { user: 'tom' } }
]
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment