Videos
TypeScript is (a superset of) JavaScript, so you just use JSON.parse as you would in JavaScript:
let obj = JSON.parse(jsonString);
Only that in TypeScript you can also have a type for the resulting object:
interface MyObj {
myString: string;
myNumber: number;
}
let obj: MyObj = JSON.parse('{ "myString": "string", "myNumber": 4 }');
console.log(obj.myString);
console.log(obj.myNumber);
(code in playground)
Type-safe JSON.parse
You can continue to use JSON.parse, as TypeScript is a superset of JavaScript:
This means you can take any working JavaScript code and put it in a TypeScript file without worrying about exactly how it is written.
There is a problem left: JSON.parse returns any, which undermines type safety (don't use any).
Here are three solutions for stronger types, ordered by ascending complexity:
1. User-defined type guards
Playground
// For example, you expect to parse a given value with `MyType` shape
type MyType = { name: string; description: string; }
// Validate this value with a custom type guard (extend to your needs)
function isMyType(o: any): o is MyType {
return "name" in o && "description" in o
}
const json = '{ "name": "Foo", "description": "Bar" }';
const parsed = JSON.parse(json);
if (isMyType(parsed)) {
// do something with now correctly typed object
parsed.description
} else {
// error handling; invalid JSON format
}
isMyType is called a type guard. Its advantage is, that you get a fully typed object inside truthy if branch.
2. Generic JSON.parse wrapper
Playground
Create a generic wrapper around JSON.parse, which takes one type guard as input and returns the parsed, typed value or error result:
const safeJsonParse = <T>(guard: (o: any) => o is T) =>
(text: string): ParseResult<T> => {
const parsed = JSON.parse(text)
return guard(parsed) ? { parsed, hasError: false } : { hasError: true }
}
type ParseResult<T> =
| { parsed: T; hasError: false; error?: undefined }
| { parsed?: undefined; hasError: true; error?: unknown }
Usage example:
const json = '{ "name": "Foo", "description": "Bar" }';
const result = safeJsonParse(isMyType)(json) // result: ParseResult<MyType>
if (result.hasError) {
console.log("error :/") // further error handling here
} else {
console.log(result.parsed.description) // result.parsed now has type `MyType`
}
safeJsonParse might be extended to fail fast or try/catch JSON.parse errors.
3. External libraries
Writing type guard functions manually becomes cumbersome, if you need to validate many different values. There are libraries to assist with this task - examples (no comprehensive list):
io-ts: hasfp-tspeer dependency, uses functional programming stylezod: strives to be more procedural / object-oriented thanio-tstypescript-is: TS transformer for compiler API, additional wrapper like ttypescript neededtypescript-json-schema/ajv: Create JSON schema from types and validate it withajv
More infos
- Runtime type checking #1573
- Interface type check with Typescript
- TypeScript: validating external data