npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@unnoen/untypedjson

v2.0.0

Published

A simple JSON deserializer and serializer for Node.js and the browser using TypeScript decorators.

Downloads

41

Readme

UntypedJSON

Typed JSON. The name is a lie.

npm workflow

A simple JSON deserializer and serializer for Node.js and the browser using TypeScript decorators.

Ever been working with JSON that uses inconsistent naming conventions? Then this is the library for you!

It supports nested classes, arrays, null/undefined values, has type safety and the ability to create custom deserializers and serializers.

It also has support for Mixins, so you can extend (multiple!) classes and override properties.

Designed to be lightweight with no dependencies. Your bundler will thank you.

Offers both CommonJS and ES Module builds, so you can use it with Node.js, Webpack, Rollup, Parcel, Vite etc.

Installation

Just use your favourite package manager:

npm

npm install @unnoen/untypedjson

pnpm

pnpm add @unnoen/untypedjson

Yarn

yarn add @unnoen/untypedjson

Usage

It's super simple to use. Just decorate your class with @JsonProperty, the name of the JSON property and the type of the property. Or set a default value for it to be inferred automatically!

Then use the DeserializeObject function to parse the JSON string or object into an instance of your class.

Or use the SerializeObject function to convert your class instance into a JSON object, ready to be stringified.

Make sure you have these options enabled in your tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Simple Types

You can either use the provided JsonType enum or the built-in String, Number, and Boolean constructors so that the parser knows how to parse the value.

Or, provide a default value to infer the type automatically!

import {DeserializeObject, JsonProperty, JsonType} from "@unnoen/untypedjson";

class Person {
    @JsonProperty('fn', JsonType.STRING) // You can use the JsonType enum...
    public name: string;

    @JsonProperty('a', Number) // ...or the built-in constructors.
    public age: number;

    // We can set a default value to infer the type automatically!
    // In this case, the parser knows it's a string.
    @JsonProperty('o')
    public occupation = 'Unemployed';
}

const jsonString = '{"fn": "John Doe", "a": 42, "o": "Software Engineer"}';

const person = DeserializeObject(jsonString, Person);

// Now we can use our own property names!
console.log(person.name); // John Doe
console.log(person.age); // 42
console.log(person.occupation); // Software Engineer

You can also import the JsonType constants directly if that's more your style.

import {DeserializeObject, JsonProperty, STRING} from "@unnoen/untypedjson";

class Person {
    @JsonProperty('fn', STRING)
    public name: string;
}

// ...

Arrays

Just wrap your type in an array. The parser will automatically detect it and parse it as an array.

import {DeserializeObject, JsonProperty, JsonType} from "@unnoen/untypedjson";

class Person {
    @JsonProperty('aka', [JsonType.STRING])
    public aliases: string[];
}

const jsonString = '{"aka": ["John", "Doe"]}';

const person = DeserializeObject(jsonString, Person);

console.log(person.aliases); // ["John", "Doe"]
console.log(person.aliases[0]); // John

Nested Classes

Just use the class as the type.

import {DeserializeObject, JsonProperty, JsonType} from "@unnoen/untypedjson";

class Person {
    @JsonProperty('fn', JsonType.STRING)
    public name: string;

    @JsonProperty('a', JsonType.NUMBER)
    public age: number;
}

class Company {
    @JsonProperty('cn', JsonType.STRING)
    public name: string;

    @JsonProperty('employees', [Person]) // You can also use them in arrays!
    public employees: Person[];
}

const jsonString = '{"cn": "ACME Inc.", "employees": [{"fn": "John Doe", "a": 42}]}';

const company = DeserializeObject(jsonString, Company);

console.log(company.name); // ACME Inc.
console.log(company.employees[0].name); // John Doe

Extending Classes

Just extend the class and use the @JsonProperty decorator on the properties you want to override.

import {DeserializeObject, JsonProperty, JsonType} from "@unnoen/untypedjson";

class Person {
    @JsonProperty('fn', JsonType.STRING)
    public name: string;

    @JsonProperty('a', JsonType.NUMBER)
    public age: number;
}

class Employee extends Person {
    @JsonProperty('s', JsonType.NUMBER)
    public salary: number;
}

const jsonString = '{"fn": "John Doe", "a": 42, "s": 100000}';

const employee = DeserializeObject(jsonString, Employee);

console.log(employee.name); // John Doe
console.log(employee.salary); // 100000

Null & Undefined Values

If you want to allow null or undefined values, just use the PropertyNullability enum.

  • PropertyNullability.MAPwill attempt to map the value to the type of the property. (default)
  • PropertyNullability.IGNORE will ignore the property if it's null or undefined.
  • PropertyNullability.PASS will pass the value as is.
import {DeserializeObject, JsonProperty, JsonType, PropertyNullability} from "@unnoen/untypedjson";

class Person {
    @JsonProperty('fn', JsonType.STRING)
    public name: string;

    @JsonProperty('a', JsonType.NUMBER, PropertyNullability.IGNORE)
    public age: number;
}

const jsonString = '{"fn": "John Doe"}';

const person = DeserializeObject(jsonString, Person);

console.log(person.name); // John Doe
console.log(person.age); // undefined

Default Values

If you want to set a default value, just set it in the initializer.

Setting a default value means you don't need to specify the type of the property; it will be inferred. (Unless you want to override it!)

Make sure to set the PropertyNullability to PropertyNullability.IGNORE so that the parser doesn't override it!

import {DeserializeObject, JsonProperty, JsonType, PropertyNullability} from "@unnoen/untypedjson";

class Person {
    @JsonProperty('fn', JsonType.STRING)
    public name: string;

    @JsonProperty('a', JsonType.NUMBER, PropertyNullability.IGNORE)
    public age: number = 42;

    @JsonProperty('o')
    public occupation = 'Unemployed';
}

const jsonString = '{"fn": "John Doe", "o": "Software Engineer"}';

const person = DeserializeObject(jsonString, Person);

console.log(person.name); // John Doe
console.log(person.age); // 42
console.log(person.occupation); // Software Engineer

Custom Deserializers & Serializers

If you want to use a custom deserializer or serializer, just extend the JsonConverter class and override the Deserialize and Serialize methods.

Make sure you implement your own type checking!

import {DeserializeObject, JsonConverter, JsonProperty, JsonType} from "@unnoen/untypedjson";

class DateConverter extends JsonConverter<Date> {
    public Serialize(value: Date): string {
        return value.toISOString();
    }

    public Deserialize(value: JsonType.STRING): Date {
        return new Date(value);
    }
}

class Person {
    @JsonProperty('fn', JsonType.STRING)
    public name: string;

    @JsonProperty('b', DateConverter)
    public birthday: Date;
}

const jsonString = '{"fn": "John Doe", "b": "1990-01-01"}';

const person = DeserializeObject(jsonString, Person);

console.log(person.name); // John Doe
console.log(person.birthday.getFullYear()); // 1990

Mixins

Ever wanted to add properties to a class from multiple other classes? Well now you can!

Use @JsonMixin to inherit properties from multiple classes. It also inherits the @JsonProperty decorators and getters/setters.

Make sure to define the interface for the class you're mixing in!

import {DeserializeObject, JsonMixin, JsonProperty, JsonType} from "@unnoen/untypedjson";

interface EmployeePerson extends Person, Employee {
} // You must define the interface otherwise the compiler will complain.

class Person {
    @JsonProperty('fn', JsonType.STRING)
    public name: string;
}

class Employee {
    @JsonProperty('s', JsonType.NUMBER)
    public salary: number;
}

@JsonMixin(Person, Employee)
class EmployeePerson {
    // This class will have the properties from Person and Employee
}

const jsonString = '{"fn": "John Doe", "s": 100000}';

const employee = DeserializeObject(jsonString, EmployeePerson);

console.log(employee.name); // John Doe
console.log(employee.salary); // 100000

Configuration

There are multiple ways to pass in options, you can do it on a per-class basis with the @JsonOptions decorator, or for the entire deserializer/serializer.

import {DeserializeObject, JsonOptions, JsonProperty, JsonType} from "@unnoen/untypedjson";

@JsonOptions({
    // Options go here...
    mapClassProperties: true,
})
class Person {
    @JsonProperty('fn', JsonType.STRING)
    public name: string;
}

const jsonString = '{"fn": "John Doe"}';

const person = DeserializeObject(jsonString, Person, {
    // ...or here.
    passUnknownProperties: true,
});

console.log(person.name); // John Doe

Options

| Option | Method | Type | Default | Description | |--------------------------|----------------------------------------------------------------|-----------------------|---------------------------|--------------------------------------------------------------------------------------| | defaultNullabilityMode | @JsonOptions | PropertyNullability | PropertyNullability.MAP | The default nullability for all properties in the class. | | mapClassProperties | @JsonOptionsDeserializeOptions | boolean | false | Whether to automatically map class properties to JSON properties if the names match. | | passUnknownProperties | @JsonOptionsDeserializeOptionsSerializeOptions | boolean | false | Whether to pass unknown properties to the class. |

Contributing

No pull request is too small!

If you want to contribute, just fork the repository and create a pull request into the main branch.

This project uses Yarn Berry for package management, however you can use npm if you want, it should work just fine.

Linting and tests are run on every commit, but don't worry if it fails! The most important part is contributing, linting issues and tests can be fixed later. :)

License

This project is licensed under the MIT License - see the LICENSE file for details

TL;DR - Do whatever you want with it. Just don't sue me if it breaks. I'd appreciate it if you could link back to this repository though. :)

Acknowledgements

  • json2typescript
    • UntypedJSON is heavily inspired by this project. I wanted a lightweight alternative and decided to make my own.