TypeDrop
2026-04-27 Challenge
2026-04-27
Easy
Typed Notification Router
You're building the notification dispatch layer for a productivity app. Raw notification payloads arrive as `unknown` from a webhook endpoint; your router must validate them, fan them out to strongly-typed per-channel handlers, and collect a discriminated-union delivery report per notification — with zero `any`.
Goals
- Define the `Notification` discriminated union with channel-specific fields for email, sms, and push variants.
- Implement `parseNotification` to narrow `unknown` → `Notification` using type guards, throwing `ValidationError` on invalid input.
- Define the `DeliveryReport` discriminated union and implement `routeNotification` with an exhaustive switch that the compiler enforces.
- Implement `processAll` to parse and route a batch, converting parse failures into `{ status: 'failed', channel: 'unknown' }` reports.
challenge.ts
// Key types & main function signatures
export type EmailNotification = {
channel: "email";
to: string;
subject: string;
body: string;
};
export type SmsNotification = { channel: "sms"; to: string; message: string };
export type PushNotification = { channel: "push"; deviceToken: string; title: string; body: string };
export type Notification = EmailNotification | SmsNotification | PushNotification;
// status:"delivered" carries sentAt; status:"failed" carries reason
export type DeliveryReport = never; // TODO — replace with discriminated union
export function parseNotification(raw: unknown): Notification { … }
export function routeNotification(n: Notification): DeliveryReport { … }
export function processAll(raws: unknown[]): DeliveryReport[] { … }
Hints (click to reveal)
Hints
- A helper like `isRecord(v: unknown): v is Record<string, unknown>` makes nested property checks safe without `as`.
- For an exhaustive switch, add a `default` branch that passes the value to a `(x: never) => never` helper — the compiler will error if any variant is unhandled.
- Use `Notification["channel"] | "unknown"` as the type for the `channel` field in `DeliveryReport` to cover the parse-failure fallback.
Useful resources
Or clone locally
git clone -b challenge/2026-04-27 https://github.com/niltonheck/typedrop.git