Multiple Generics In Typescript Type

Building a library that lets you pull in all of your analytics events and make Typesafe queries of them, running into a problem with multiple generics Events is a key, object pair which stores information about the events
type AnalyticsEvents = typeof events;

type AnalyticsEvent = AnalyticsEvents[keyof AnalyticsEvents];

type SamplingOptions = "TotalCount"

type Filter<T extends keyof AnalyticsEvents> = {
name: AnalyticsEvents[T]["properties"][number]["name"];
compare: "equals";
value: string | number | boolean;
};

type SeriesEntry<T extends keyof AnalyticsEvents> = {
name: T;
sampling?: SamplingOptions;
where?: Filter<T> | Filter<T>[];
};

type InsightOptions<T extends keyof AnalyticsEvents> = {
events: SeriesEntry<T> | SeriesEntry<T>[];
filters?: [];
breakdownBy?: AnalyticsEvents[T]["properties"][number]["name"];
};

function fetchInsight<T extends keyof AnalyticsEvents>(
options: InsightOptions<T>
) {}
type AnalyticsEvents = typeof events;

type AnalyticsEvent = AnalyticsEvents[keyof AnalyticsEvents];

type SamplingOptions = "TotalCount"

type Filter<T extends keyof AnalyticsEvents> = {
name: AnalyticsEvents[T]["properties"][number]["name"];
compare: "equals";
value: string | number | boolean;
};

type SeriesEntry<T extends keyof AnalyticsEvents> = {
name: T;
sampling?: SamplingOptions;
where?: Filter<T> | Filter<T>[];
};

type InsightOptions<T extends keyof AnalyticsEvents> = {
events: SeriesEntry<T> | SeriesEntry<T>[];
filters?: [];
breakdownBy?: AnalyticsEvents[T]["properties"][number]["name"];
};

function fetchInsight<T extends keyof AnalyticsEvents>(
options: InsightOptions<T>
) {}
Given above, the following should error in the second where since Answer Overflow Acount Id doesn't exist on autocapture, but since I can only do one generic it uses the combined type for both
fetchInsight({
events: [
{
name: "User Grant Consent",
sampling: "TotalCount",
where: {
name: "Answer Overflow Account Id",
compare: "equals",
value: 123,
},
},
{
name: "$autocapture",
where: {
name: "Answer Overflow Account Id",
compare: "equals",
value: 123,
},
},
],
});
fetchInsight({
events: [
{
name: "User Grant Consent",
sampling: "TotalCount",
where: {
name: "Answer Overflow Account Id",
compare: "equals",
value: 123,
},
},
{
name: "$autocapture",
where: {
name: "Answer Overflow Account Id",
compare: "equals",
value: 123,
},
},
],
});
7 Replies
Rhys
RhysOP12mo ago
The problem is with
function fetchInsight<T extends keyof AnalyticsEvents>(
options: InsightOptions<T>
) {}
function fetchInsight<T extends keyof AnalyticsEvents>(
options: InsightOptions<T>
) {}
I can't think of a way to make it do the generic on a per event basis, maybe I could do something with a builder pattern? Source code also https://github.com/RhysSullivan/analytics-renderer
GitHub
GitHub - RhysSullivan/analytics-renderer
Contribute to RhysSullivan/analytics-renderer development by creating an account on GitHub.
Rhys
RhysOP12mo ago
Here's the events array:
Rhys
RhysOP12mo ago
Maybe a syntax like would work?
No description
Rhys
RhysOP12mo ago
i realize now that this is literally just Drizzle for PostHog
Rhys
RhysOP12mo ago
This works but the types are wrong
No description
Rhys
RhysOP12mo ago
No description
Rhys
RhysOP12mo ago
function execute<T extends AnalyticsEventNames>(series: SeriesEntry<T>[]) {
console.log("series", series);
return [
{
hello: "world",
},
];
}

function addSeries<
Current extends AnalyticsEventNames,
Existing extends AnalyticsEventNames,
Next extends AnalyticsEventNames
>(
series: SeriesEntry<Current>,
existingSeries?: SeriesEntry<Existing> | SeriesEntry<Existing>[]
) {
const existing = Array.isArray(existingSeries)
? existingSeries
: existingSeries
? [existingSeries]
: [];
return {
addSeries: (series: SeriesEntry<Next>) =>
addSeries(series, [...existing, series]),
execute: () => execute([...existing, series]),
};
}
function execute<T extends AnalyticsEventNames>(series: SeriesEntry<T>[]) {
console.log("series", series);
return [
{
hello: "world",
},
];
}

function addSeries<
Current extends AnalyticsEventNames,
Existing extends AnalyticsEventNames,
Next extends AnalyticsEventNames
>(
series: SeriesEntry<Current>,
existingSeries?: SeriesEntry<Existing> | SeriesEntry<Existing>[]
) {
const existing = Array.isArray(existingSeries)
? existingSeries
: existingSeries
? [existingSeries]
: [];
return {
addSeries: (series: SeriesEntry<Next>) =>
addSeries(series, [...existing, series]),
execute: () => execute([...existing, series]),
};
}
Want results from more Discord servers?
Add your server