TypeDrop

2026-08-12 Challenge

2026-08-12 Easy

Typed Safe JSON Parser with Result & Schema Validation

You're building the data-ingestion layer for a configuration management tool. Raw JSON strings arrive from multiple untrusted sources (files, environment variables, API responses) and must be safely parsed, validated against a known shape, and returned as a typed `Result<T, ParseError>` — never throwing, never widening to `unknown` without a guard.

Goals

  • Implement the `InferSchema<S>` conditional mapped type that converts a schema descriptor object into its corresponding TypeScript type.
  • Implement `safeParseJSON` so it wraps `JSON.parse` in a try/catch and always returns a typed `Result` — never throwing.
  • Implement `validateShape` to check each field's runtime type against its `FieldKind` descriptor and return a `ValidationError` naming the first failing field.
  • Compose both utilities in `parseAndValidate` to form a single safe pipeline that propagates either error kind without losing type information.
challenge.ts
// Core Result type & error union
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };

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

// Schema descriptor → inferred TS type (your job to implement!)
type FieldKind = "string" | "number" | "boolean" | "string[]";

type InferSchema<S extends Record<string, FieldKind>> = {
  [K in keyof S]: never; // TODO: map each FieldKind to its TS type
};

// Functions you must implement:
declare function safeParseJSON(raw: string): Result<unknown, ParseError>;

declare function validateShape<S extends Record<string, FieldKind>>(
  value: unknown,
  schema: S
): Result<InferSchema<S>, ParseError>;

declare function parseAndValidate<S extends Record<string, FieldKind>>(
  raw: string,
  schema: S
): Result<InferSchema<S>, ParseError>;
Hints (click to reveal)

Hints

  • For `InferSchema`, use a mapped type `[K in keyof S]: ...` combined with a conditional type `S[K] extends "string" ? string : S[K] extends "number" ? number : ...`.
  • In `safeParseJSON`, catch the error as `unknown`, then check `instanceof Error` to safely read `.message` before constructing your `SyntaxParseError`.
  • In `validateShape`, iterate over `Object.keys(schema)` and use `typeof (obj as Record<string, unknown>)[key]` to check each field — one localised assertion is acceptable inside this function only.

Or clone locally

git clone -b challenge/2026-08-12 https://github.com/niltonheck/typedrop.git