Let's say I have this AnalyticsService class
export class AnalyticsService {
static sendAnalytics(eventName: string) {
console.log(eventName);
// logic here...
}
static EVENTS = {
Header: {
LogoClicked: "Header: Logo Clicked",
},
UserMenu: {
LoginButtonClicked: "User Menu: Login Button Clicked",
LogoutButtonClicked: "User Menu: Logout Button Clicked",
}
};
}
And I use this class to send analytics like:
AnalyticsService.sendAnalytics(AnalyticsService.EVENTS.Header.LogoClicked)
I want to extract all values of EVENTS to a union type
to make sure that sendAnalytics function gets only existing event names
for example, the results here should be:
"Header: Logo Clicked" | "User Menu: Login Button Clicked" | "User Menu: Logout Button Clicked"
Is it even possible with typescript?
If it is, is it going to significantly reduce the typescript performance when it's a pretty big object?
Edit: just to clarify the EVENTS object can be really nested (I gave a tiny example just for simplicity )
Here is how you could do to correctly type sendAnalytics:
type Keys = typeof AnalyticsService.EVENTS[keyof typeof AnalyticsService.EVENTS]
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type FlattenedEvents = UnionToIntersection<Keys>;
type EventNames = FlattenedEvents[keyof FlattenedEvents];
export class AnalyticsService {
static sendAnalytics(eventName: EventNames) {
console.log(eventName);
// logic here...
}
static EVENTS = {
Header: {
LogoClicked: "Header: Logo Clicked",
},
UserMenu: {
LoginButtonClicked: "User Menu: Login Button Clicked",
LogoutButtonClicked: "User Menu: Logout Button Clicked",
}
} as const;
}
AnalyticsService.sendAnalytics(AnalyticsService.EVENTS.Header.LogoClicked); // OK
AnalyticsService.sendAnalytics('test'); // KO