ts.data.json
June 28, 2025 ยท View on GitHub
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.
Documentation
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.
Installation
npm install ts.data.json --save
Quick Example
You can play with this example in this stackblitz playground.
One import to rule them all
import * as JsonDecoder from 'ts.data.json';
Define your types
interface Address {
street: string;
city: string;
country: string;
postalCode: string;
}
Create decoders for each type
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'
);
Infer your types
You can also infer the types from its decoders!
type User = JsonDecoder.FromDecoder<typeof userDecoder>;
Decode a valid API response
// Valid API response
const apiResponse = {
id: 123,
email: 'marty@mcfly.com',
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);
});
Output
Welcome back, Marty McFly!
Your last login was: 10/26/1985, 1:21:00 AM
Decode an invalid API response
// Invalid API response
const invalidResponse = {
id: 'not-a-number', // Should be a number
email: 'marty@mcfly.com',
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);
});
Output
Validation failed: <User> decoder failed at key "id" with error: "not-a-number" is not a valid number