Skip to content

joanllenas/ts.data.json

 
 

Repository files navigation

ts.data.json

Build codecov npm version bundle size npm downloads

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: '[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);
  });

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: '[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);
  });

Output

Validation failed: <User> decoder failed at key "id" with error: "not-a-number" is not a valid number

Related libraries

About

A lightweight JSON decoding library for TypeScript

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 98.6%
  • Other 1.4%