TypeScript type annotations offer compile-time guarantees. However, when data flows into our applications from external sources, various issues can still occur at runtime.
JSON decoders validate incoming JSON before it enters the application. This way, if the data has an unexpected structure, we're immediately alerted.
The documentation site is auto-generated with TSDoc comments using TypeDoc. You'll find documentation for v2.3.1, v3 and later.
Planning to migrate to v3? Be sure to read the v3 migration guide.
If you're new to JSON decoding, you should read the introductory article Decoding JSON with TypeScript, which, although somewhat dated, clearly explains how and why to use this library.
npm install ts.data.json --save
You can play with this example in this stackblitz playground.
import * as JsonDecoder from 'ts.data.json';
interface Address {
street: string;
city: string;
country: string;
postalCode: string;
}
const addressDecoder = JsonDecoder.object<Address>(
{
street: JsonDecoder.string(),
city: JsonDecoder.string(),
country: JsonDecoder.string(),
postalCode: JsonDecoder.string()
},
'Address'
);
const userDecoder = JsonDecoder.object(
{
id: JsonDecoder.number(),
email: JsonDecoder.string(),
name: JsonDecoder.string(),
age: JsonDecoder.optional(JsonDecoder.number()),
address: addressDecoder,
tags: JsonDecoder.array(JsonDecoder.string(), 'string[]'),
isActive: JsonDecoder.boolean(),
lastLogin: JsonDecoder.nullable(JsonDecoder.string().map(str => new Date(str)))
},
'User'
);
You can also infer the types from its decoders!
type User = JsonDecoder.FromDecoder<typeof userDecoder>;
// Valid API response
const apiResponse = {
id: 123,
email: '[email protected]',
name: 'Marty McFly',
age: 17,
address: {
street: '123 Main St',
city: 'San Francisco',
country: 'USA',
postalCode: '94105'
},
tags: ['user', 'premium'],
isActive: true,
lastLogin: '1985-10-26T01:21:00Z'
};
// Decode the response
userDecoder
.decodePromise(apiResponse)
.then((user: User) => {
log(`Welcome back, ${user.name}!`);
log(`Your last login was: ${user.lastLogin?.toLocaleString()}`);
})
.catch(error => {
console.error('Failed to decode user data:', error);
});
Welcome back, Marty McFly!
Your last login was: 10/26/1985, 1:21:00 AM
// Invalid API response
const invalidResponse = {
id: 'not-a-number', // Should be a number
email: '[email protected]',
name: 'Marty McFly',
age: 17,
address: {
street: '123 Main St',
city: 'San Francisco',
country: 'USA',
postalCode: '94105'
},
tags: ['user', 'premium'],
isActive: true,
lastLogin: '1985-10-26T01:21:00Z'
};
// Decode the response
userDecoder
.decodePromise(invalidResponse)
.then(() => {
log('User decoded successfully');
})
.catch(error => {
log(`Validation failed: ${error}`, true);
});
Validation failed: <User> decoder failed at key "id" with error: "not-a-number" is not a valid number