CodingNeed.
Mid · Language concepts

Validate untrusted JSON at the boundary

Accept unknown input. Return {ok:true,value:{name,age}} only for a non-array object whose name trims to nonempty text and age is an integer from 0 through 130. Otherwise return {ok:false,error:"Invalid learner"}. Ignore extra fields.

Examples

Normalize: {"name":" Ada ","age":37,"admin":true} → {"ok":true,"value":{"name":"Ada","age":37}}
Null: null → {"ok":false,"error":"Invalid learner"}

Compare approaches

Baseline approach

Exception-driven validation has similar asymptotic cost but mixes expected validation failures with exceptions. Compare clarity and error handling, not only speed.

Time: O(k) name length · Space: O(k)

function solve(input:unknown):unknown {
 try {
  if(input===null||typeof input!=="object"||Array.isArray(input))throw new Error();
  const row=input as Record<string,unknown>;
  if(typeof row.name!=="string"||!row.name.trim())throw new Error();
  if(typeof row.age!=="number"||!Number.isInteger(row.age)||row.age<0||row.age>130)throw new Error();
  return {ok:true,value:{name:row.name.trim(),age:row.age}};
 }catch{return {ok:false,error:"Invalid learner"};}
}
Refined approach

JSON arriving over HTTP is untrusted even when your TypeScript interface looks precise. Start with unknown, narrow object and null separately, and validate each field before constructing a trusted result. Return a discriminated union instead of mixing null, exceptions and half-valid objects. This playground transpiles types; use tsc --strict in a project to check the compile-time guarantees.

Time: O(k) for name length k. · Space: O(k) for normalized output.

type Result = {ok:true;value:{name:string;age:number}} | {ok:false;error:string};
function solve(input: unknown): Result {
  if (typeof input === "object" && input !== null && !Array.isArray(input)) {
    const row = input as Record<string, unknown>;
    if (typeof row.name === "string" && row.name.trim().length > 0 &&
        typeof row.age === "number" && Number.isInteger(row.age) && row.age >= 0 && row.age <= 130) {
      return {ok:true, value:{name:row.name.trim(), age:row.age}};
    }
  }
  return {ok:false, error:"Invalid learner"};
}

Common traps

  • JSON.parse(text) as Learner does not validate anything at runtime.
Practise in the workspace →