{"id":13528364,"url":"https://github.com/edcarroll/ta-json","last_synced_at":"2025-05-12T03:32:16.323Z","repository":{"id":56271502,"uuid":"77763697","full_name":"edcarroll/ta-json","owner":"edcarroll","description":"Type-aware JSON serializer/parser","archived":false,"fork":false,"pushed_at":"2023-01-26T15:53:21.000Z","size":97,"stargazers_count":67,"open_issues_count":11,"forks_count":16,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-10-28T13:36:37.689Z","etag":null,"topics":["classes","decorators","es2016","es7","javascript","json","parser","serializer","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/edcarroll.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-01T02:52:29.000Z","updated_at":"2022-12-26T11:00:54.000Z","dependencies_parsed_at":"2023-02-14T19:15:56.497Z","dependency_job_id":null,"html_url":"https://github.com/edcarroll/ta-json","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edcarroll%2Fta-json","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edcarroll%2Fta-json/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edcarroll%2Fta-json/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edcarroll%2Fta-json/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/edcarroll","download_url":"https://codeload.github.com/edcarroll/ta-json/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223931318,"owners_count":17227231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["classes","decorators","es2016","es7","javascript","json","parser","serializer","typescript"],"created_at":"2024-08-01T06:02:28.119Z","updated_at":"2024-11-10T08:31:47.225Z","avatar_url":"https://github.com/edcarroll.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Type-Aware JSON Parser \u0026 Serializer (ta-json)\n\n\u003ca href=\"https://www.npmjs.com/package/ta-json\"\u003e\n  \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/v/ta-json.svg?style=flat-square\" /\u003e\n\u003c/a\u003e\n\u003ca href=\"https://travis-ci.org/edcarroll/ta-json\"\u003e\n  \u003cimg alt=\"Travis CI\" src=\"https://img.shields.io/travis/edcarroll/ta-json.svg?style=flat-square\" /\u003e\n\u003c/a\u003e\n\nStrongly typed JSON parser \u0026 serializer for TypeScript / ES7 via decorators.\n\nSupports [parameterized class constructors](#jsonobject), nesting classes, [inheritance](#jsondiscrimatorpropertypropertystring--jsondiscriminatorvaluevalueany), [`Array`s and `Set`s](#jsonelementtypetypefunction), [custom property converters](#jsonconverterconverteripropertyconverter--parameterlessconstructor) and more.\n\n## Installation\n\n```sh\n$ npm install --save ta-json\n```\n\n## Quickstart\n\nImport the necessary decorators and the JSON object from the library, and set up your class.\n\n```typescript\nimport { JSON, JsonObject, JsonProperty } from \"ta-json\";\n\n@JsonObject()\nexport class Person {\n    @JsonProperty()\n    public firstName:string;\n\n    @JsonProperty()\n    public lastName:string;\n\n    public get fullName() {\n        return `${this.firstName} ${this.lastName}`;\n    }\n\n    // Note this parameterized constructor\n    constructor(fullName:string) {\n        let [firstName, lastName] = fullName.split(\" \");\n        this.firstName = firstName;\n        this.lastName = lastName;\n    }\n}\n```\n\nParse and stringify with the provided JSON class. Note that you can use this class to work with untyped objects as usual.\n\n```typescript\nlet person = new Person(\"Edward Carroll\");\nJSON.stringify(person); // {\"firstName\":\"Edward\",\"lastName\":\"Carroll\"}\n\nlet fromJson = JSON.parse\u003cPerson\u003e('{\"firstName\":\"Edward\",\"lastName\":\"Carroll\"}', Person);\nperson instanceof Person; // true\nperson.fullName; // Edward Carroll\n```\n\nFor more advanced usage please read the docs below for each of the available decorators.\n\n## Overriding the `JSON` object\n\nThis library doesn't make any changes to the global scope, it merely exports its main class with the same name, allowing it to be a drop in replacement for `JSON` (without any decorators, the library falls back to default functionality).\n\nIf you'd prefer to import the library with a different name, you can also import `TaJson`, which will give you the same class.\n\n```typescript\nimport { TaJson } from \"ta-json\";\n```\n\n## Decorators\n\n### @JsonObject()\n\nRegisters the class with the serializer. Classes don't need to have parameterless constructors to be serialized and parsed - however this means that the internal state of a class must be fully represented by its serialized fields.\n\nIf you would like to run functions before and after deserialization, please see [@BeforeDeserialized()](#beforedeserialized) and [@OnDeserialized()](#ondeserialized)\n\n#### Usage\n\n```typescript\nimport { JsonObject } from \"ta-json\";\n\n@JsonObject()\nexport class Person {}\n```\n\n### @JsonProperty(serializedName?:string)\n\nProperties are mapped on an opt-in basis. *Only properties that are decorated are serialized*. The name for the property in the serialized document can optionally be specified using this decorator.\n\n#### Usage\n\n```typescript\nimport { JsonObject, JsonProperty } from \"ta-json\";\n\n@JsonObject()\nexport class Person {\n    @JsonProperty(\"fullName\")\n    public name:string;\n\n    @JsonProperty()\n    public get firstName() {\n        return this.name.split(\" \").shift();\n    }\n}\n```\n\n### @JsonType(type:Function)\n\nSpecifies the type to be used when serializing a property. Useful when you want to serialize the field using a different type than the type of the property itself, for example an entity reference.\n\n#### Usage\n\n```typescript\nimport { JsonObject, JsonProperty, JsonType } from \"ta-json\";\n\n@JsonObject()\nexport class Person {\n    @JsonProperty()\n    @JsonType(String)\n    public name:string;\n}\n```\n\n### @JsonElementType(type:Function)\n\nSpecifies the type to be used when serializing elements of an `Array` or `Set`. This is a required decorator when working with these types due to how metadata reflection works.\n\n#### Usage\n\n```typescript\nimport { JsonObject, JsonProperty, JsonElementType } from \"ta-json\";\n\n@JsonObject()\nexport class LotteryDraw {\n    @JsonProperty()\n    @JsonElementType(Number)\n    public numbers:Set\u003cnumber\u003e;\n}\n```\n\n### @JsonDiscrimatorProperty(property:string) \u0026 @JsonDiscriminatorValue(value:any)\n\nThese decorators are used when you want to deserialize documents while respecting the class inheritance hierarchy. The discriminator property is used to determine the type of the document, and the descriminator value is set on each subclass (or deeper subclasses) so the document can be matched to the appropriate class.\n\nMulti-level inheritance is fully supported, by the @JsonDiscriminatorValue and the @JsonDiscriminatorProperty decorators being applied to the same class.\n\n#### Usage\n\n```typescript\nimport { JSON, JsonObject, JsonProperty, JsonDiscriminatorProperty, JsonDiscriminatorValue } from \"ta-json\";\n\nexport enum AnimalType { Cat = 0, Dog = 1 }\n\n@JsonObject()\n@JsonDiscriminatorProperty(\"type\")\nexport class Animal {\n    @JsonProperty()\n    type:AnimalType;\n}\n\n@JsonObject()\n@JsonDiscriminatorValue(AnimalType.Cat)\nexport class Cat extends Animal {\n    constructor() {\n        super();\n        this.type = AnimalType.Cat;\n    }\n}\n\n@JsonObject()\n@JsonDiscriminatorValue(AnimalType.Dog)\nexport class Dog extends Animal {\n    constructor() {\n        super();\n        this.type = AnimalType.Dog;\n    }\n}\n\nlet animals = [new Cat(), new Dog()];\n\nJSON.stringify(animals); // [{\"type\":0},{\"type\":1}]\nJSON.parse\u003cAnimal[]\u003e('[{\"type\":0},{\"type\":1}]', Animal); // [ Cat { type: 0 }, Dog { type: 1 } ]\n```\n\n### @BeforeDeserialized()\n\nSpecifies the method to run before a document has been deserialized into a class, but after the class has been instantiated. This is useful for setting default values that may be overwritten by the deserialization.\n\n#### Usage\n\n```typescript\nimport { JsonObject, JsonProperty, BeforeDeserialized } from \"ta-json\";\n\n@JsonObject()\nexport class Demo {\n    @JsonProperty()\n    public serialized:string;\n\n    @BeforeDeserialized()\n    public setDefaults() {\n        this.serialized = \"default value\";\n    }\n}\n```\n\n### @OnDeserialized()\n\nSpecifies the method to run once a document has been deserialized into a class. This is useful for example when recalculating private members that aren't serialized into JSON.\n\n#### Usage\n\n```typescript\nimport { JsonObject, JsonProperty, OnDeserialized } from \"ta-json\";\n\n@JsonObject()\nexport class Demo {\n    private _unserialized:string;\n\n    @JsonProperty()\n    public serialized:string;\n\n    @OnDeserialized()\n    public onDeserialized() {\n        this._unserialized = doOperation(this.serialized);\n    }\n}\n```\n\n### @JsonConstructor()\n\nSpecifies the method to be *optionally* run before a document has been deserialized. The specified method is only run when `runConstructor` is set to `true` in the parse options.\n\n#### Usage\n\n```typescript\nimport { JSON, JsonObject, JsonProperty, JsonConstructor } from \"ta-json\";\n\n@JsonObject()\nexport class Demo {\n    @JsonProperty()\n    public example:string;\n\n    constructor(example:string) {\n        this.defaultValues(example);\n    }\n\n    @JsonConstructor()\n    private defaultValues(example:string = \"default\") {\n        this.example = example;\n    }\n}\n\nJSON.parse\u003cDemo\u003e('{}', Demo, { runConstructor: true }); // Demo { example: 'default' }\nJSON.parse\u003cDemo\u003e('{\"example\":\"different\"}', Demo, { runConstructor: true }) // Demo { example: 'different' }\nJSON.parse\u003cDemo\u003e('{}', Demo); // Demo {}\n```\n\n### @JsonConverter(converter:IPropertyConverter | ParameterlessConstructor\u003cIPropertyConverter\u003e)\n\nProperty converters can be used to define how a type is serialized / deserialized. They must implement the `IPropertyConverter` interface, and output a `JsonValue`.\n\nThere are two built in converters, `DateConverter` and `BufferConverter`. They are applied automatically when serializing `Date` and `Buffer` objects.\n\n#### Example\n\nThis example uses the built in `BufferConverter`, to output Buffer values as base64 encoded strings. Note that when parsing documents, the deserializer will convert the value back into a Buffer.\n\n```typescript\nimport { JSON, JsonObject, JsonProperty, JsonConverter, BufferConverter } from \"ta-json\";\n\n@JsonObject()\nexport class ConverterDemo {\n    @JsonProperty()\n    @JsonConverter(new BufferConverter(\"base64\"))\n    public bufferValue:Buffer;\n\n    constructor(value:string) {\n        this.bufferValue = Buffer.from(value);\n    }\n}\n\nlet demo = new ConverterDemo(\"hello, world!\");\nJSON.stringify(demo); // {\"bufferValue\":\"aGVsbG8sIHdvcmxkIQ==\"}\nlet parsed = JSON.parse\u003cConverterDemo\u003e('{\"bufferValue\":\"aGVsbG8sIHdvcmxkIQ==\"}', ConverterDemo);\nparsed.bufferValue instanceof Buffer; // true\nparsed.bufferValue.toString(); // hello, world!\n```\n\n#### Usage\n\nBelow we define a converter that reverses any string value it is given.\n\n```typescript\nimport { JSON, JsonObject, JsonProperty, JsonConverter, IPropertyConverter } from \"ta-json\";\n\nexport class ReverseStringConverter implements IPropertyConverter {\n    public serialize(property:string):string {\n        return property.split('').reverse().join('');\n    }\n\n    public deserialize(value:string):string {\n        return value.split('').reverse().join('');\n    }\n}\n\n@JsonObject()\nexport class Demo {\n    @JsonProperty()\n    @JsonConverter(ReverseStringConverter)\n    public example:string;\n}\n\nlet d = new Demo();\nd.example = \"hello\";\nJSON.stringify(d); // {\"example\":\"olleh\"}\n```\n\nNote that you can also provide an instance of a property converter, for example if you want to customize the output. (This is how the `BufferConverter` chooses a string encoding).\n\n### @JsonReadonly()\n\nThe use of this decorator stops the property value being read from the document by the deserializer.\n\n#### Usage\n\n```typescript\nimport { JSON, JsonObject, JsonProperty, JsonReadonly } from \"ta-json\";\n\n@JsonObject()\nexport class Person {\n    @JsonProperty()\n    @JsonReadonly()\n    public name:string;\n}\n\nJSON.parse\u003cPerson\u003e('{\"name\":\"Edward\"}', Person).name; // undefined\n```\n\n### @JsonWriteonly()\n\nThe use of this decorator stops the property value being written to the document by the serializer. Useful for password fields for example.\n\n#### Usage\n\n```typescript\nimport { JSON, JsonObject, JsonProperty, JsonReadonly } from \"ta-json\";\n\n@JsonObject()\nexport class User {\n    @JsonProperty()\n    @JsonWriteonly()\n    public password:string;\n}\n\nlet u = new User();\nu.password = \"p4ssw0rd\";\n\nJSON.stringify(u); // {}\nJSON.parse\u003cUser\u003e('{\"password\":\"p4ssw0rd\"}', User).password; // p4ssw0rd\n```\n\n## API\n\n### JSON (can also be imported with `TaJson`)\n\n#### #stringify(value:any):string\n\nSerializes an object or array into a JSON string. If type definitions aren't found for a given object it falls back to `global.JSON.stringify(value)`.\n\n#### #parse\u003cT\u003e(json:string, type?:Function, options?:IParseOptions):T\n\nParses a JSON string into an instance of a class. the `type` parameter specifies which class to instantiate; however this is an optional parameter and as with `#stringify` it will fall back to `global.JSON.parse(json)`.\n\n##### IParseOptions\n\n* runConstructor:boolean - specifies whether the method decorated with @JsonConstructor() is run upon class initialisation. **Default `false`**\n\n#### #serialize(value:any):any\n\nSerializes an object or array into a `JsonValue`. This is an intermediary step; i.e. `global.JSON.stringify` can be called on the returned object to get a JSON string. This function is useful when returning from inside an express (o.e) middleware.\n\n#### #deserialize\u003cT\u003e(object:any, type?:Function, options?:IParseOptions):T\n\nSimilarly to the above, this function can be run on objects produced by `global.JSON.parse`, returning the same output as `#parse`. This function is useful in combination with body parsing modules, where the raw JSON has already been parsed into an object.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedcarroll%2Fta-json","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fedcarroll%2Fta-json","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedcarroll%2Fta-json/lists"}