TypeDrop
2026-04-04 Challenge
2026-04-04
Easy
Typed User Profile Merger
You're building the account-settings feature for a SaaS app. When a user submits a partial profile update, your engine must validate the raw incoming fields, deep-merge them onto the existing profile, and return a fully typed `Result<T, E>` — with zero `any`.
Goals
- Define `ProfileUpdate` as a mapped/utility type that makes all user-editable `UserProfile` fields optional while excluding `id` and `updatedAt`.
- Define `MergeError` as a discriminated union with three `kind` variants, each carrying appropriate detail fields.
- Implement the three type-predicate validators (`validateEmail`, `validateHttpsUrl`, `validatePlatform`) with correct narrowing signatures.
- Implement `mergeProfile` to validate all incoming fields in order, return typed `MergeError` on the first failure, and return a new immutable `UserProfile` with a refreshed `updatedAt` on success.
challenge.ts
/** Supported social-link platforms. */
type Platform = "github" | "twitter" | "linkedin";
interface SocialLink { platform: Platform; url: string; }
interface UserProfile {
id: string; displayName: string; email: string;
bio: string; avatarUrl: string; socials: SocialLink[];
updatedAt: string; // system-managed
}
// All user-editable fields are optional; id & updatedAt are excluded
type ProfileUpdate = Omit<Partial<UserProfile>, "id" | "updatedAt">;
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
type MergeError =
| { kind: "INVALID_EMAIL"; provided: string }
| { kind: "INVALID_URL"; field: string; provided: string }
| { kind: "UNKNOWN_PLATFORM"; provided: string };
declare function mergeProfile(
existing: UserProfile,
update: ProfileUpdate
): Result<UserProfile, MergeError>;
Hints (click to reveal)
Hints
- For `ProfileUpdate`, you only need two built-in utility types composed in a single expression — think about which one makes fields optional and which one removes fields.
- A type predicate has the return type `value is SomeType`; your `validatePlatform` predicate should narrow `string` all the way down to the `Platform` union.
- In `mergeProfile`, validate fields in order and `return` early on the first error — you never need a nested `if/else` tree.
Useful resources
Or clone locally
git clone -b challenge/2026-04-04 https://github.com/niltonheck/typedrop.git