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.