Skip to content

Repository files navigation

ts.data.json

Build codecov socket.dev npm version bundle size npm downloads

TypeScript types vanish at runtime, so the moment JSON crosses into your app from an API, a file, or localStorage, those compile-time guarantees are gone. ts.data.json puts them back: you describe the shape you expect with a decoder, and it validates the data at the boundary, handing you a fully typed value or a precise error.

All your JSON are belong to us

Features

  • Tiny & tree-shakeable -- zero dependencies, ships ESM + CJS, sideEffects: false. You bundle only the decoders you import.
  • Rich, structured errors -- every failure is a { message, path } issue, and all failures are reported at once, not just the first.
  • Standard Schema compliant -- decoders implement the Standard Schema spec, so they drop straight into any Standard-Schema-aware tool.
  • Type inference -- derive your static types from the decoders themselves with FromDecoder. No duplicate interfaces to keep in sync.

Installation

npm install ts.data.json

Quick example

One import gives you every decoder:

import * as JsonDecoder from 'ts.data.json';

Describe the shape you expect, then let TypeScript infer the type from it:

const userDecoder = JsonDecoder.object({
  id: JsonDecoder.number(),
  name: JsonDecoder.string(),
  roles: JsonDecoder.array(JsonDecoder.string()),
  lastLogin: JsonDecoder.nullable(JsonDecoder.string().map(iso => new Date(iso)))
});

// No separate interface needed:
type User = JsonDecoder.FromDecoder<typeof userDecoder>;
// { id: number; name: string; roles: string[]; lastLogin: Date | null }

Decode trusted-looking data and get back a typed value:

const result = userDecoder.decode({
  id: 123,
  name: 'Marty McFly',
  roles: ['user', 'premium'],
  lastLogin: '1985-10-26T01:21:00Z'
});

if (result.isOk()) {
  const user: User = result.value;
  console.log(`Welcome back, ${user.name}!`);
}

When the data is wrong, you get structured issues that point at exactly what failed:

const result = userDecoder.decode({
  id: 'not-a-number', // should be a number
  name: 'Marty McFly',
  roles: ['user', 42], // 42 should be a string
  lastLogin: null
});

if (!result.isOk()) {
  result.issues.forEach(issue => {
    console.log(`${JsonDecoder.formatIssuePath(issue.path)}: ${issue.message}`);
  });
  // id: "not-a-number" is not a valid number
  // roles[1]: 42 is not a valid string
}

Documentation

Full, auto-generated API docs and guides live on the documentation site:

New to JSON decoding? The introductory article Decoding JSON with TypeScript explains the how and why (slightly dated, but the ideas still hold).

Related libraries

License

Released under the BSD-3-Clause license.

Releases

Used by

Contributors

Languages