Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

json2typescript

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json2typescript - npm Package Compare versions

Comparing version 0.9.1 to 0.9.2

.npmignore

3

package.json
{
"name": "json2typescript",
"version": "0.9.1",
"version": "0.9.2",
"description": "Provides TypeScript methods to map a JSON string to a JavaScript object on runtime",

@@ -33,3 +33,2 @@ "keywords": [

"devDependencies": {
"typescript": "2.0.0"
},

@@ -36,0 +35,0 @@ "main": "index.js",

# json2typescript
**json2typescript** is a small package containing a helper class that maps json objects to an instance of a TypeScript class. The idea is that we only need a simple function call in order to fill a json string into nested objects in TypeScript.
In Angular 2 applications, everyone consumes JSON API's from an external source.
Type checking and object mapping is only possible in TypeScript, but not in the JavaScript runtime.
As the API may change at any point, it is important for larger projects to verify the consumed data.
**json2typescript** is a small package containing a helper class that maps JSON objects to an instance of a TypeScript class.
After compiling to JavaScript, the result will still be an instance of this class.
With **json2typescript**, only a simple function call is necessary, as demonstrated in this TypeScript snippet:
```typescript
// Assume that you have a class named User defined at some point
// Assume that you get a JSON string from a webservice
let str: string = ...;
// Now you can map the string to the object automatically
let user: User = JsonConvert.deserializeString(str, User);
console.log(user); // prints User{ ... } in JavaScript runtime, not Object{ ... }
```
---
## Dependencies
# Changelog
We developed **json2typescript** for Angular2. In this document, we only cover this use case. However, you may use our package for pure TypeScript or even JavaScript applications.
* v0.9.2: Added method `serializeString()`, changed `property` names and behaviour
* v0.9.1: First version released to the public
---
# Getting started
## Requirements
We developed **json2typescript** for Angular2. In this document, we only cover this use case. However, you may use our package for pure TypeScript or even JavaScript applications.
## Setup a Test Application

@@ -20,8 +44,359 @@

cd testApplication
npm install json2typescript
```
Our package makes use of TypeScript decorators. Please activate them in your **tsconfig.json** under `compilerOptions` as follows:
```json
{
"compilerOptions": {
[...]
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
[...]
}
```
Now you are ready to use the package.
## Mapping example
In order to use the **json2typescript** package, all you need to do is write decorators and import the package. The following things need to be done if you would like to map JSON to existing classes:
* Classes need to be preceeded by `@JsonObject`
* Properties need to be preceeded by `@JsonProperty(key, Type)`
* Properties need to have a default value (or undefined), otherwise the mapper will not work
See below an example so you can learn from it how **json2typescript** works best.
Assuming that you have created the **testApplication** in the step before and installed **json2typescript** as suggested, create a class in a new file **city.ts** with the following content:
```typescript
import {JsonObject, JsonProperty} from "json2typescript";
@JsonObject
export class City {
// This property has no @JsonProperty.
// It will only be mapped if our JSON object contains a key named "id".
// If there is no such element, no exception is thrown.
// There will be no type checking at all.
public id: number = undefined; // <- assign a value or undefined to enable the mapper!
// This maps the value of the JSON key "name" to the class property "name".
// If the JSON value is not of type string (or missing), there will be an exception.
@JsonProperty("name", String)
public name: string = undefined;
// This maps the JSON key "founded" to the private class property "_founded".
// Note the use of public getter and setter.
// If the JSON value is not of type number (or missing), there will be an exception.
@JsonProperty("founded", Number)
private _founded: number = undefined;
public get founded() { return this._founded; }
public set founded(value: number) { this._founded = value; }
// This maps the JSON key "beautiful" to the class property "beautiful".
// If the JSON value is not of type boolean (or missing), there will be an exception.
@JsonProperty("beautiful", Boolean)
public beautiful: boolean = undefined;
// This maps the JSON key "data" to the class property "data".
// We are not sure about the type, so we omit the second parameter.
// There will be an exception if the JSON value is missing.
@JsonProperty("data") // is the same as @JsonProperty("data", undefined)
public data: any = undefined;
// This maps the JSON key "keywords" to the class property "keywords".
// This is an example of a string array. Note our syntax "[String]".
// In the further examples at the end of this document, you can see how to nest complex arrays.
@JsonProperty("keywords", [String])
public keywords: string[] = undefined; // or Array<string>
public printInfo() {
if (this.beautiful)
console.log(this.name + " was founded in " + this.founded + " and is really beautiful!");
else
console.log(this.name + " was founded in " + this.founded + ".");
}
}
```
Now create a file **country.ts** with the following content:
```typescript
import {JsonObject, JsonProperty} from "json2typescript";
@JsonObject
export class Country {
// This maps the value of the JSON key "countryName" to the class property "name".
// If the JSON value is not of type string (or missing), there will be an exception.
@JsonProperty("countryName", String)
public name: string = undefined;
// This maps the value of the JSON key "cities" to the class property "cities".
// If the JSON value is not of type array object (or missing), there will be an exception.
// There will be an exception too if the objects in the array do not match the class "City".
@JsonProperty("cities", [City])
public cities: City[] = undefined;
}
```
Then navigate to the file **app.component.ts** and add the following code:
```typescript
import { Component } from '@angular/core';
import { JsonConvert } from "json2typescript"
import { City } from "./city";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
ngOnInit() {
// Define a JSON string (could come from a HTTP service)
let jsonString = `
{
"countryName": "Switzerland",
"cities": [
{
"id": 1,
"name": "Basel",
"founded": -200,
"beautiful": true,
"data": 123,
"keywords": ["Rhine", "River"]
},
{
"id": 1,
"name": "Zurich",
"founded": 0,
"beautiful": false,
"data": "no",
"keywords": ["Limmat", "Lake"]
}
]
}`;
// Choose your settings
// Check the detailed reference in the chapter "JsonConvert class properties and methods"
JsonConvert.debugMode = true; // print some debug data
JsonConvert.ignorePrimitiveChecks = false; // don't allow assigning number to string etc.
JsonConvert.valueCheckingMode = JsonConvert.ValueCheckingMode.DISALLOW_NULL; // never allow null
// Map to the country class
let country: Country;
try {
country = JsonConvert.deserializeString(jsonString, Country);
country.cities[0].printInfo(); // prints: Basel was founded in -200 and is really beautiful!
} catch (e) {
console.log((<Error>e));
}
}
```
Play around with the JSON to provocate exceptions when deserializing the string.
# Detailed reference
## Class and property decorators
Decorators should be used whenever you would like to assign a JSON value to a TypeScript class instance property.
### Class decorators
The class decorators are used infront of the class declaration and do not support any parameters:
```typescript
@JsonObject
export class User {}
```
> Tip: Make sure you import `JsonObject` from `json2typescript`.
### Property decorators
Property decorators are a vital part for type checking. It is important that the type in the decorator matches the TypeScript type.
```typescript
@JsonObject
export class User {
@JsonProperty("jsonKeyOfName", String)
public name: string = undefined;
}
```
Note: You must assign any value or `undefined` to your property at initialization, otherwise our mapper does **not** work.
#### First parameter: json key
The first parameter of `@JsonProperty` is the JSON object key.
It happens that the keys given by the server are very ugly.
Here you can map any key to the `User` property `name`.
In our case, `json[jsonKeyOfName]` gets mapped to `user[name]`.
#### Second parameter: expected type
The second parameter of `@JsonProperty` is the expected type.
Make sure you pass the class name and not an instance of the class.
In case of primitive types, you have to use the upper case names.
See the following cheat sheet for reference:
| Expected type | TypeScript type |
| --- | :--- |
| String | string |
| Number | number |
| Boolean | boolean |
| User | User |
| undefined | any |
| | |
| [String] | string[] |
| [Number] | number[] |
| [Boolean] | boolean[] |
| [User] | User[] |
| [undefined] or [] | any[] |
At first, our array notation on the left looks odd.
But this notation allows you to define even nested arrays.
See the examples at the end of this document for more info about nesting arrays.
#### Important notes
* Make sure you define the expected type as accurate as possible, even if you expect primitive types.
* By default, casting primitives into other primitives is not allowed. Check the public properties below in this document to change this behaviour.
* By default, primitives are not allowed to be null. Check the public properties below in this document to change this.
* If you don't know the type, you may use `undefined` as expected type. You may also omit the second parameter of `@JsonProperty`.
#### More about the array syntax
* You can allow arrays by using the bracket notation combined with the types as seen above. For example: `[String]` for a string array
* Mixing arrays is allowed. For example: `[String, Number]` for an array where the first entry is a string, the second is a number.
* If the real array is longer than indicated here, the last type will be forced to the rest of the array entries (above: `Number`).
* This means, `[String, Number]` is equivalent to `[String, Number, Number]` and so on.
* Nesting arrays and objects are allowed. For example: `[[String, Number], User]`.
* This is equivalent to `[[String, Number, Number], User, User]` and so on.
* As further example, `[[String]]` is equal to `[[String],[String]]` which is equal to `[[String,String], [String,String]]` and so on.
* If an array has less elements as given in the expected type, no exception is thrown.
* For example, if we define `[String]` or the equivalent `[String, String]` no exception is thrown - even if the JSON gives us an empty array.
> Tip: See the examples at the end of this document for advanced examples for nesting arrays.
## JsonConvert class properties and methods
### Public properties
`(bool) JsonConvert.debugMode`
Determines whether debugging info is shown in console when parsing a JSON object.
The default value is `false`.
`(bool) JsonConvert.ignorePrimitiveChecks`
Determines whether primitive types should be checked.
If true, it will be allowed to assign primitive to other primitive types.
The default is `false`.
`(bool) JsonConvert.valueCheckingMode`
Determines which types are allowed to be null.
You may assign three different values:
* `JsonConvert.ValueCheckingMode.ALLOW_NULL`: All given values can be null.
* `JsonConvert.ValueCheckingMode.ALLOW_OBJECT_NULL`: Objects can be null, but primitive types cannot be null.
* `JsonConvert.ValueCheckingMode.DISALLOW_NULL`: No null values are tolerated.
The default is `JsonConvert.ValueCheckingMode.ALLOW_OBJECT_NULL`.
> The TypeScript developer team suggests you to avoid null values. If your JSON api doesn't return null values, you should try the last flag disallowing null values.
### Public methods
`(string) public static serializeObject(instance: Object)`
Tries to serialize a JavaScript object to a JSON string.
`(any) public static deserializeString(jsonString: string, classObject: { new(): any })`
Tries to deserialize a JSON string to a TypeScript class.
`(any) public static deserializeObject(jsonObject: Object, classObject: { new(): any })`
Tries to deserialize a JSON object to a TypeScript class.
---
[ WILL BE EXPANDED SOON ]
# Further examples
In case you don't have enough complex examples yet, you may find some more in this section.
## Nesting arrays
It is heavily discouraged to use nested arrays and use different types in a JSON api.
If you need them anyway, here is how you have to define the types:
### 1) Nested arrays with same type
In the following example, `jsonKeyOfWeirdKeywords` is a key in the JSON object defined like this:
```JSON
{
"jsonKeyOfWeirdKeywords": [
["Hello", "World"],
["Bye", "Earth"]
]
}
```
As we have an array of array of strings, you can define the expected type like this:
```typescript
@JsonObject
export class User {
@JsonProperty("jsonKeyOfWeirdKeywords", [[String, String], [String, String]])
public keywords: any = undefined;
}
```
> Tip: In our syntax, `[[String, String], [String, String]]` is equivalent to `[[String], [String]]` and `[[String]]`. That is because the last type in an array will be automatically repeated as much as needed.
### 2) Nested array with mixed depth and type
In the following example, `JSONKeyOfWeirdKeywords` is a key in the JSON object defined like this:
```JSON
{
"jsonKeyOfWeirdKeywords": [
["FC", "Basel"],
1893
]
}
```
You can define the expected type in your class like this:
```typescript
@JsonObject
export class User {
@JsonProperty("jsonKeyOfWeirdKeywords", [[String, String], Number])
public keywords: any = undefined;
}
```
> Tip: In our syntax, `[[String, String], Number]` is equivalent to `[[String], Number]`.
---
# Imprint
This package was created by the **Digital Humanities Lab** of **University of Basel** in 2016.
We make use of it in our new website of
http://www.salsah.org.
More information on
http://dhlab.unibas.ch
/**
* Offers a simple API for mapping json objects to TypeScript/JavaScript classes and vice versa.
* @author Andreas Aeschlimann, DHlab, University of Basel, Switzerland
* @version 0.9.1
* @version 0.9.2
* @licence MIT

@@ -11,5 +11,26 @@ * @see https://www.npmjs.com/package/json2typescript full documentation

/**
* Helper class for value checking mode.
*/
public static ValueCheckingMode = class {
/**
* Readonly flag for JsonConvert.ValueCheckingMode.valueChecking property.
* All given values can be null.
*/
public static readonly ALLOW_NULL: number = 1;
/**
* Readonly flag for JsonConvert.ValueCheckingMode.valueChecking property.
* Objects can be null, but primitive types cannot be null.
*/
public static readonly ALLOW_OBJECT_NULL: number = 2;
/**
* Readonly flag for JsonConvert.ValueCheckingMode.valueChecking property.
* No null values are tolerated.
*/
public static readonly DISALLOW_NULL: number = 3;
}
/**
* Determines whether debugging info is shown in console.
*/
public static debug: boolean = false;
public static debugMode: boolean = false;

@@ -23,11 +44,14 @@ /**

/**
* Determines whether all types (also primitives) are allowed to be null.
* If false, only custom non-primitive types are allowed to be null.
* Determines which types are allowed to be null.
* You may assign three different values:
* JsonConvert.ValueCheckingMode.ALLOW_NULL: All given values can be null.
* JsonConvert.ValueCheckingMode.ALLOW_OBJECT_NULL: Objects can be null, but primitive types cannot be null.
* JsonConvert.ValueCheckingMode.DISALLOW_NULL: No null values are tolerated.
*/
public static allowPrimitiveNull: boolean = false;
public static valueCheckingMode: number = JsonConvert.ValueCheckingMode.ALLOW_OBJECT_NULL;
/**
* Tries to serialize a JavaScript object to a json string.
* Tries to serialize a JavaScript object to a JSON string.
* @param instance any instance of a class
* @returns {string} the json string
* @returns {string} the JSON string
* @see https://www.npmjs.com/package/json2typescript full documentation

@@ -37,3 +61,3 @@ */

if (JsonConvert.debug) {
if (JsonConvert.debugMode) {
console.log("----------");

@@ -46,3 +70,3 @@ console.log("Receiving JavaScript object:");

if (JsonConvert.debug) {
if (JsonConvert.debugMode) {
console.log("Returning JSON string:");

@@ -58,18 +82,48 @@ console.log(jsonString);

/**
* Tries to deserialize a json object to a JavaScript class.
* @param json the json object or string
* @param classObject the class object
* @returns the deserialized object
* Tries to deserialize a JSON string to a TypeScript class.
* @param jsonString the JSON string
* @param classObject the object class
* @returns {any} the deserialized object instance
* @throws an exception in case of failure
* @see https://www.npmjs.com/package/json2typescript full documentation
*/
public static deserializeObject(json: any, classObject: { new(): any }): any {
public static deserializeString(jsonString: string, classObject: { new(): any }): any {
// Create an object from json string if necessary
let jsonObject: Object;
if (typeof(json) === "string") jsonObject = JSON.parse(json);
else jsonObject = json;
if (typeof(jsonString) !== "string") {
throw new Error(
"Fatal error in JsonConvert. " +
"Passed parameter jsonString in JsonConvert.deserializeString() is not of type string."
);
}
if (JsonConvert.debug) {
console.log("----------");
if (JsonConvert.debugMode) {
console.log("Receiving JSON string:");
console.log(jsonString);
}
// Create an object from json string
let jsonObject = JSON.parse(jsonString);
return JsonConvert.deserializeObject(jsonObject, classObject);
}
/**
* Tries to deserialize a JSON object to a TypeScript class.
* @param jsonObject the JSON object
* @param classObject the object class
* @returns {any} the deserialized object instance
* @throws an exception in case of failure
* @see https://www.npmjs.com/package/json2typescript full documentation
*/
public static deserializeObject(jsonObject: any, classObject: { new(): any }): any {
if (typeof(jsonObject) !== "object") {
throw new Error(
"Fatal error in JsonConvert. " +
"Passed parameter jsonObject in JsonConvert.deserializeObject() is not of type object."
);
}
if (JsonConvert.debugMode) {
console.log("Receiving JSON object:");

@@ -86,6 +140,5 @@ console.log(jsonObject);

if (JsonConvert.debug) {
if (JsonConvert.debugMode) {
console.log("Returning CLASS instance:");
console.log(classInstance);
console.log("----------");
}

@@ -97,6 +150,7 @@

/**
* Tries to deserialize a json object property to a JavaScript class.
* Tries to find the JSON mapping for a given class property and finally assign the value.
* @param classInstance the instance of the class
* @param propertyKey the property
* @param json the json object
* @param json the JSON object
* @throws throws an expection in case of failure
*/

@@ -109,3 +163,3 @@ private static deserializeObject_loopProperty(classInstance: any, propertyKey: string, json: Object): void {

// Check if a object-json mapping is possible for a property
// Check if a object-JSON mapping is possible for a property
if (JsonConvert.deserializeObject_propertyHasDecorator(mapping, propertyKey) === false) {

@@ -128,5 +182,5 @@ classInstance[propertyKey] = json[propertyKey];

"Fatal error in JsonConvert. " +
"Failed to map the json object to the class \"" + classInstance.constructor.name + "\" because the defined json property \"" + jsonKey + "\" does not exist:\n\n" +
"Failed to map the JSON object to the class \"" + classInstance.constructor.name + "\" because the defined JSON property \"" + jsonKey + "\" does not exist:\n\n" +
"\tClass property: \n\t\t" + propertyKey + "\n\n" +
"\tJson property: \n\t\t" + jsonKey
"\tJSON property: \n\t\t" + jsonKey
);

@@ -142,8 +196,8 @@ }

"Fatal error in JsonConvert. " +
"Failed to map the json object to the class \"" + classInstance.constructor.name + "\" because of a type error.\n\n" +
"Failed to map the JSON object to the class \"" + classInstance.constructor.name + "\" because of a type error.\n\n" +
"\tClass property: \n\t\t" + propertyKey + "\n\n" +
"\tExpected type: \n\t\t" + JsonConvert.deserializeObject_getExpectedType(expectedType) + "\n\n" +
"\tJson property: \n\t\t" + jsonKey + "\n\n" +
"\tJson type: \n\t\t" + JsonConvert.deserializeObject_getJsonType(jsonValue) + "\n\n" +
"\tJson value: \n\t\t" + JSON.stringify(jsonValue) + "\n\n" +
"\tJSON property: \n\t\t" + jsonKey + "\n\n" +
"\tJSON type: \n\t\t" + JsonConvert.deserializeObject_getJsonType(jsonValue) + "\n\n" +
"\tJSON value: \n\t\t" + JSON.stringify(jsonValue) + "\n\n" +
e.message

@@ -156,3 +210,3 @@ );

* Check if a class property has a decorator.
* @param mapping the class-json mapping array
* @param mapping the class-JSON mapping array
* @param propertyKey the property key

@@ -166,6 +220,6 @@ * @returns {boolean} true if the mapping exists, otherwise false

/**
* Tries to map a json property to a class property.
* Checks the type of the json value and compares it to the expected value.
* Tries to map a JSON property to a class property.
* Checks the type of the JSON value and compares it to the expected value.
* @param expectedType the expected type for the property indicated in the decorator
* @param jsonValue the json object for the given property
* @param jsonValue the JSON object for the given property
* @returns returns the resulted mapped property

@@ -181,3 +235,3 @@ * @throws throws an expection in case of failure

// Check if it the attempt was 1-d
// Check if attempt and expected was 1-d
if (expectedType instanceof Array === false && jsonValue instanceof Array === false) {

@@ -189,10 +243,18 @@

// Check if we have null value
if (jsonValue === null) return null;
if (jsonValue === null) {
if (JsonConvert.valueCheckingMode !== JsonConvert.ValueCheckingMode.DISALLOW_NULL)
return null;
else throw new Error("\tReason: JSON value is null.");
}
return JsonConvert.deserializeObject(jsonValue, expectedType);
} else if (expectedType === Object || expectedType === undefined) { // general object
} else if (expectedType === null || expectedType === Object || expectedType === undefined) { // general object
// Check if we have null value
if (jsonValue === null) return null;
if (jsonValue === null) {
if (JsonConvert.valueCheckingMode !== JsonConvert.ValueCheckingMode.DISALLOW_NULL)
return null;
else throw new Error("\tReason: JSON value is null.");
}

@@ -204,4 +266,6 @@ return jsonValue;

// Check if we have null value
if (JsonConvert.allowPrimitiveNull && jsonValue === null) return null;
else if (jsonValue === null) throw new Error("\tReason: Primitive type mapping failed because the json value was null.");
if (jsonValue === null) {
if (JsonConvert.valueCheckingMode === JsonConvert.ValueCheckingMode.ALLOW_NULL) return null;
else throw new Error("\tReason: JSON value is null.");
}

@@ -217,3 +281,3 @@ // Check if the types match

if (JsonConvert.ignorePrimitiveChecks) return jsonValue;
throw new Error("\tReason: Primitive type mapping failed because the type from the json object does not match the expected type.");
throw new Error("\tReason: JSON object does not match the expected primitive type.");
}

@@ -223,3 +287,3 @@

throw new Error("\tReason: Primitive type mapping failed because the provided type is unknown.");
throw new Error("\tReason: Expected type is unknown.");

@@ -230,3 +294,3 @@ }

// Check if it the attempt was n-d
// Check if attempt and expected was n-d
if (expectedType instanceof Array && jsonValue instanceof Array) {

@@ -260,5 +324,19 @@

// Check if attempt was 1-d and expected was n-d
if (expectedType instanceof Array) {
if (jsonValue === null) {
if (JsonConvert.valueCheckingMode !== JsonConvert.ValueCheckingMode.DISALLOW_NULL) return null;
else throw new Error("\tReason: JSON value is null.");
}
throw new Error("\tReason: Expected type is array, but JSON value is non-array.");
}
// Check if attempt was n-d and expected as 1-d
if (jsonValue instanceof Array) {
throw new Error("\tReason: JSON value is array, but expected a non-array type.");
}
// All other attempts are fatal
throw new Error(
"\tReason: Array mapping failed because the array type from the json object does not match the expected array type."
"\tReason: Mapping failed because of an unknown error."
);

@@ -300,4 +378,4 @@

/**
* Returns a string representation of the json value.
* @param jsonValue the json value
* Returns a string representation of the JSON value.
* @param jsonValue the JSON value
* @returns {string} the string representation

@@ -328,3 +406,3 @@ */

/**
* Decorator of a class that comes from a json object.
* Decorator of a class that comes from a JSON object.
* @param target the class

@@ -338,3 +416,3 @@ * @see https://www.npmjs.com/package/json2typescript full documentation

/**
* Decorator of a class property that comes from a json object.
* Decorator of a class property that comes from a JSON object.
* Use the following notation for the type:

@@ -344,3 +422,3 @@ * Primitive type: String|Number|Boolean

* Array type: [String|Numer|Boolean|YourClassName]
* @param jsonKey the key in the expected json object
* @param jsonKey the key in the expected JSON object
* @param type the expected type String|Boolean|Number|any

@@ -347,0 +425,0 @@ * @see https://www.npmjs.com/package/json2typescript full documentation

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc