TypeDrop

2026-05-16 Challenge

2026-05-16 Easy

Typed User Session Aggregator

You're building the analytics layer for a SaaS dashboard. Raw session events arrive as `unknown` from a browser telemetry API; your engine must validate them, group them by user, and return a strongly-typed per-user session summary report — with zero `any`.

Goals

  • Declare the `UserId` branded type and a `Result<T, E>` discriminated union from the provided stubs.
  • Implement `validateSessionEvent` to safely narrow `unknown` → `SessionEvent`, returning typed success or failure.
  • Define `EventCounts` as a mapped type over `EventCategory` (no hand-written properties).
  • Implement `aggregateSessions` to group valid events by user and produce a fully-typed `AggregationReport` with correct totals, revenue, unique paths, and sorted summaries.
challenge.ts

// Key types you'll work with:

export type EventCategory = "pageview" | "click" | "error" | "purchase";

export type UserId = string & { readonly _brand: "UserId" };

export type Result<T, E> =
  | { ok: true;  value: T }
  | { ok: false; error: E };

export type EventCounts = { [K in EventCategory]: number }; // mapped type

export interface UserSessionSummary {
  readonly userId: UserId;
  readonly totalEvents: number;
  readonly eventCounts: EventCounts;
  readonly firstSeen: number;
  readonly lastSeen: number;
  readonly totalRevenueCents: number;
  readonly uniquePaths: ReadonlyArray<string>;
}

// Functions you must implement:
export function validateSessionEvent(raw: unknown): Result<SessionEvent, string> { ... }
export function aggregateSessions(rawEvents: unknown[]): AggregationReport { ... }
Hints (click to reveal)

Hints

  • For `EventCounts`, think `{ [K in EventCategory]: number }` — a single mapped type expression covers all four categories at once.
  • To validate the `category` field at runtime without `any`, define a `const CATEGORIES: ReadonlyArray<EventCategory>` tuple and use `.includes()` after narrowing to `string`.
  • A `Map<UserId, UserSessionSummary>` (or a mutable intermediate type) is a clean way to accumulate per-user data; convert it to a sorted array at the end.

Or clone locally

git clone -b challenge/2026-05-16 https://github.com/niltonheck/typedrop.git