TypeDrop
2026-03-10 Challenge
2026-03-10
Easy
Typed Contact Book Merger
You're building the import feature for a personal CRM app. Users can sync contacts from multiple sources (phone, email, LinkedIn), and your job is to validate raw unknown input, merge duplicate contacts by email, and produce a clean, strongly-typed contact list — all with zero `any`.
Goals
- Implement `isContactSource` as a type guard that narrows `unknown` to the `ContactSource` union.
- Implement `parseRawContact` to validate every field of an unknown record and return a typed `ParseResult<Contact>` with normalised values.
- Implement `mergeContacts` to run the parser over all raw records, collect failures, and merge duplicate contacts by email using a `Map` — keeping the first non-null phone and unioning sources.
challenge.ts
export type ContactSource = "phone" | "email" | "linkedin";
export interface Contact {
email: string;
name: string;
phone: string | null;
sources: ContactSource[];
}
export type ParseResult<T> =
| { ok: true; value: T }
| { ok: false; error: string };
// Narrows an unknown value to a ContactSource literal
export function isContactSource(value: unknown): value is ContactSource { /* TODO */ }
// Validates & normalises a single unknown record
export function parseRawContact(raw: unknown): ParseResult<Contact> { /* TODO */ }
// Merges an array of unknown records, deduplicating by email
export function mergeContacts(
rawRecords: unknown[]
): { contacts: Contact[]; failures: Array<{ ok: false; error: string }> } { /* TODO */ }
Hints (click to reveal)
Hints
- A type guard function returns `value is SomeType` — use `===` checks against each literal string to narrow `ContactSource`.
- In `parseRawContact`, check `typeof raw === 'object' && raw !== null && !Array.isArray(raw)` first, then use `'email' in raw` before accessing any property.
- Use `new Map<string, Contact>()` in `mergeContacts` and `new Set(existing.sources)` to deduplicate sources when merging a duplicate email.
Useful resources
Or clone locally
git clone -b challenge/2026-03-10 https://github.com/niltonheck/typedrop.git