TypeDrop

2026-02-24 Challenge

2026-02-24 Easy

Typed Contact Book Lookup

You're building a small contact book utility for an internal HR tool. Given a list of contacts with varying optional fields, you must build a strongly-typed lookup index and implement search/filter helpers — the challenge is in the types, not the logic.

Goals

  • Define `ContactIndex`, `ContactSummary`, and `SearchFilters` using the `Record`, `Pick`, and `Partial` built-in utility types respectively.
  • Implement `buildIndex` to convert a `Contact[]` into a `ContactIndex` keyed by each contact's `id`.
  • Implement `summarise` to extract only the `id`, `name`, `email`, and `department` fields from every contact in a `ContactIndex`.
  • Implement `filterContacts` to return contacts matching ALL provided filter fields, with special subset-matching logic for the optional `tags` array.
challenge.ts
/** The department a contact belongs to. */
type Department = "engineering" | "design" | "marketing" | "hr" | "finance";

/** A contact's role seniority. */
type Seniority = "junior" | "mid" | "senior" | "lead" | "manager";

interface Contact {
  id: string;
  name: string;
  email: string;
  department: Department;
  seniority: Seniority;
  phone?: string;
  tags?: string[];
}

// Your job: define these three types using built-in utility types...
type ContactIndex  = Record<string, Contact>;       // TODO: use Record<>
type ContactSummary = Pick<Contact, "id" | ...>;    // TODO: use Pick<>
type SearchFilters  = Partial<Contact>;             // TODO: use Partial<>

// ...then implement these three functions:
function buildIndex(contacts: Contact[]): ContactIndex { ... }
function summarise(index: ContactIndex): ContactSummary[] { ... }
function filterContacts(contacts: Contact[], filters: SearchFilters): Contact[] { ... }
Hints (click to reveal)

Hints

  • For `filterContacts`, iterate over the keys of the `filters` object with `Object.keys` — but remember each value may be `undefined` (Partial!), so skip those keys entirely.
  • When checking `tags`, `Array.prototype.every` paired with `Array.prototype.includes` is your friend for verifying that all filter tags exist on the contact.
  • The `Pick` utility type takes a type and a union of string literal keys: `Pick<Contact, 'id' | 'name'>` — make sure you only name the four required fields for `ContactSummary`.

Or clone locally

git clone -b challenge/2026-02-24 https://github.com/niltonheck/typedrop.git