TypeDrop

2026-07-26 Challenge

2026-07-26 Easy

Typed Safe JSON Parser with Result Type

You're building the configuration-loading layer for a CLI tool. Raw JSON strings arrive from config files, environment variables, and remote endpoints — any of which can be malformed or structurally wrong. You need a small, strongly-typed parsing toolkit that turns `unknown` blobs into validated, shaped data without ever reaching for `any` or unsafe type assertions.

Goals

  • Define a two-variant discriminated-union Result<T, E> and a three-kind ParseError union.
  • Implement safeParseJSON that maps empty input, syntax failures, and valid JSON to the correct Result variants.
  • Build validateString, validateNumber, validateBoolean, and a generic validateObject using a mapped-type schema.
  • Compose everything in parseTo<T> and implement the generic mapResult helper.
challenge.ts
// Core types you must define and implement:

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

type ParseError =
  | { kind: "SyntaxError";     message: string }
  | { kind: "ValidationError"; message: string }
  | { kind: "EmptyInput";      message: string };

type Validator<T> = (value: unknown) => Result<T, ParseError>;

// Compose them all in the top-level entry point:
function parseTo<T>(
  raw: string,
  validator: Validator<T>
): Result<T, ParseError> { ... }

// Example schema-driven object validator:
const configValidator = validateObject<{ host: string; port: number }>({
  host: validateString,
  port: validateNumber,
});
Hints (click to reveal)

Hints

  • The schema parameter of validateObject should be typed as `{ [K in keyof T]: Validator<T[K]> }` — let the mapped type do the heavy lifting so callers get field-level type checking for free.
  • In validateObject, after confirming the input is a non-null, non-array object, iterate over Object.keys(schema) and run each validator — cast the field lookup with a keyof assertion only where the compiler can't narrow automatically.
  • mapResult only needs a single if/else on `result.ok` — the discriminated union will narrow both branches for you with no type assertions needed.

Or clone locally

git clone -b challenge/2026-07-26 https://github.com/niltonheck/typedrop.git