json2typescript
Advanced tools
Comparing version 1.4.1 to 1.5.0-rc.0
{ | ||
"name": "json2typescript", | ||
"version": "1.4.1", | ||
"version": "1.5.0-rc.0", | ||
"description": "Provides TypeScript methods to map a JSON object to a JavaScript object on runtime", | ||
@@ -20,8 +20,8 @@ "keywords": [ | ||
], | ||
"author": "dhlab@unibas.ch", | ||
"author": "AppVision GmbH", | ||
"license": "MIT", | ||
"homepage": "http://dhlab.unibas.ch", | ||
"homepage": "https://appvision.ch", | ||
"scripts": { | ||
"test": "karma start karma.conf.js", | ||
"build": "npm run test && tsc && npx downlevel-dts . ts3.4 && cp -r ts3.4/* . && rm -r ts3.4", | ||
"build": "npm i && npm run test && tsc -p tsconfig.json && tsc -p tsconfig-cjs.json && npx downlevel-dts . ts3.4 && cp -r ts3.4/* . && rm -r ts3.4", | ||
"dist": "npm run build && npm pack" | ||
@@ -34,26 +34,22 @@ }, | ||
"devDependencies": { | ||
"@types/jasmine": "^3.5.10", | ||
"downlevel-dts": "^0.4.0", | ||
"jasmine": "3.5.0", | ||
"karma": "^5.0.1", | ||
"@types/jasmine": "^3.8.1", | ||
"downlevel-dts": "^0.7.0", | ||
"jasmine": "3.8.0", | ||
"karma": "^6.3.4", | ||
"karma-chrome-launcher": "^3.1.0", | ||
"karma-jasmine": "3.1.1", | ||
"karma-jasmine": "4.0.1", | ||
"karma-mocha-reporter": "^2.2.5", | ||
"karma-typescript": "^5.0.2", | ||
"karma-typescript": "^5.5.1", | ||
"phantomjs-prebuilt": "^2.1.16", | ||
"typescript": "3.8.3" | ||
"typescript": "4.3.5" | ||
}, | ||
"main": "index.js", | ||
"main": "./lib/cjs/index.js", | ||
"module": "./lib/esm/index.js", | ||
"files": [ | ||
"src/json2typescript/*.d.ts", | ||
"src/json2typescript/*.map", | ||
"src/json2typescript/*.js", | ||
"index.d.ts", | ||
"index.js.map", | ||
"index.js" | ||
"lib/" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/dhlab-basel/json2typescript" | ||
"url": "https://github.com/appvision-gmbh/json2typescript" | ||
} | ||
} |
554
README.md
@@ -1,2 +0,2 @@ | ||
[![npm](https://img.shields.io/npm/v/json2typescript.svg)](https://www.npmjs.com/package/json2typescript) | ||
[![npm](https://img.shields.io/npm/v/json2typescript.svg)](https://www.npmjs.com/package/json2typescript) | ||
![](https://img.shields.io/npm/dt/json2typescript.svg?style=flat) | ||
@@ -8,8 +8,9 @@ ![](https://img.shields.io/bundlephobia/minzip/json2typescript.svg?style=flat) | ||
In Angular 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. | ||
In Angular 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. One big advantage of this approach is, that you can also use methods of this class. | ||
**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. One big advantage of this | ||
approach is, that you can also use methods of this class. | ||
@@ -22,3 +23,3 @@ With **json2typescript**, only a simple function call is necessary, as demonstrated in this TypeScript snippet: | ||
let jsonStr: string = ...; | ||
let jsonObj: object = JSON.parse(jsonStr); | ||
let jsonObj: any = JSON.parse(jsonStr); | ||
@@ -31,4 +32,3 @@ // Now you can map the json object to the TypeScript object automatically | ||
> Tip: All `serialize()` and `deserialize()` methods may throw an `Error` in case of failure. | ||
Make sure you catch errors in production! | ||
> Tip: All `serialize()` and `deserialize()` methods may throw an `Error` in case of failure. Make sure you catch errors in production! | ||
@@ -41,6 +41,9 @@ --- | ||
> Tip: We earlier suggested to use the `@JsonObject(classId)` decorator, but did not enforce it. | ||
Since v1.4.0, this is mandatory in order to make (de)serialization work properly with class inheritance. | ||
In versions above v1.2.0 and below v1.4.0, it is possible to run into issues when not using the decorator. | ||
> Warning: If you are reading this document on GitHub, it might be ahead of the published NPM version. | ||
> Please refer to the [ReadMe on NPM](https://www.npmjs.com/package/json2typescript) if in doubt. | ||
> Warning: We earlier suggested to use the `@JsonObject(classId)` decorator, but did not enforce it. | ||
> Since v1.4.0, this is mandatory in order to make (de)serialization work properly with class inheritance. | ||
> In versions above v1.2.0 and below v1.4.0, it is possible to run into issues when not using the decorator. | ||
--- | ||
@@ -52,9 +55,9 @@ | ||
We developed **json2typescript** for Angular 2+ and Ionic 2+. In this document, we only cover this use case. | ||
However, you may use our package for pure TypeScript or even JavaScript applications. | ||
We developed **json2typescript** for Angular 2+ and Ionic 2+. 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 | ||
We recommend to use the official **angular cli** tool in order to set up a new Angular project. | ||
Then, all you need to do is type the following into your operating system's terminal: | ||
We recommend to use the official **angular cli** tool in order to set up a new Angular project. Then, all you need to do | ||
is type the following into your operating system's terminal: | ||
@@ -68,4 +71,4 @@ ```sh | ||
Our package makes use of TypeScript decorators. | ||
If not done already, please activate them in your **tsconfig.json** under `compilerOptions` as follows: | ||
Our package makes use of TypeScript decorators. If not done already, please activate them in your **tsconfig.json** | ||
under `compilerOptions` as follows: | ||
@@ -75,11 +78,12 @@ ```json | ||
"compilerOptions": { | ||
[...] | ||
"experimentalDecorators": true, | ||
"emitDecoratorMetadata": true, | ||
[...] | ||
[ | ||
... | ||
] | ||
"experimentalDecorators": true, | ||
"emitDecoratorMetadata": true, | ||
[...] | ||
} | ||
``` | ||
> Tip: We have tried to make the compiler options of `json2typescript` to be as strict as possible. | ||
This enables you to use compiler options such as `"strictNullChecks": true` or `"noImplicitAny": true` in your own project. | ||
> Tip: We have tried to make the compiler options of `json2typescript` to be as strict as possible. This enables you to use compiler options such as `"strictNullChecks": true` or `"noImplicitAny": true` in your own project. | ||
@@ -90,7 +94,7 @@ Now you are ready to use the package. | ||
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: | ||
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(classIdentifier)` | ||
* Properties need to be preceeded by `@JsonProperty(jsonProperty, conversionOption, isOptional)` | ||
* Properties need to be preceeded by `@JsonProperty(jsonProperty, conversionOption, convertingMode)` | ||
* Properties need to have a default value (or undefined), otherwise the mapper will not work | ||
@@ -100,6 +104,7 @@ | ||
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: | ||
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"; | ||
import { JsonObject, JsonProperty } from "json2typescript"; | ||
@@ -116,4 +121,4 @@ @JsonObject("City") | ||
@JsonProperty("name", String) | ||
name: string = undefined; | ||
name: string = ""; | ||
// This maps the JSON key "founded" to the private class property "_founded". | ||
@@ -123,11 +128,12 @@ // Note the use of public getter and setter. | ||
@JsonProperty("founded", Number) | ||
private _founded: number = undefined; | ||
private _founded: number = 0; | ||
get founded() { return this._founded; } | ||
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) | ||
beautiful: boolean = undefined; | ||
beautiful: boolean = false; | ||
// This maps the JSON key "data" to the class property "data". | ||
@@ -138,3 +144,3 @@ // We are not sure about the type, so we omit the second parameter. | ||
data: any = undefined; | ||
// This maps the JSON key "keywords" to the class property "keywords". | ||
@@ -144,4 +150,4 @@ // This is an example of a string array. Note our syntax "[String]". | ||
@JsonProperty("keywords", [String]) | ||
keywords: string[] = undefined; // or Array<string> | ||
keywords: string[] = []; // or Array<string> | ||
printInfo() { | ||
@@ -153,3 +159,3 @@ if (this.beautiful) | ||
} | ||
} | ||
@@ -161,4 +167,4 @@ ``` | ||
```typescript | ||
import {City} from "./city"; | ||
import {JsonObject, JsonProperty} from "json2typescript"; | ||
import { City } from "./city"; | ||
import { JsonObject, JsonProperty } from "json2typescript"; | ||
@@ -171,4 +177,4 @@ @JsonObject("Country") | ||
@JsonProperty("countryName", String) | ||
name: string = undefined; | ||
name: string = ""; | ||
// This maps the value of the JSON key "cities" to the class property "cities". | ||
@@ -178,4 +184,4 @@ // If the JSON value is not of type array object (or missing), there will be an exception. | ||
@JsonProperty("cities", [City]) | ||
cities: City[] = undefined; | ||
cities: City[] = []; | ||
} | ||
@@ -187,5 +193,5 @@ ``` | ||
```typescript | ||
import {Component, OnInit} from '@angular/core'; | ||
import {JsonConvert, OperationMode, ValueCheckingMode} from "json2typescript" | ||
import {Country} from "./country"; | ||
import { Component, OnInit } from '@angular/core'; | ||
import { JsonConvert, OperationMode, ValueCheckingMode } from "json2typescript" | ||
import { Country } from "./country"; | ||
@@ -200,24 +206,24 @@ @Component({ | ||
// Define a JSON object (could come from a HTTP service, parsed with JSON.parse() if necessary) | ||
const jsonObject: object = { | ||
const jsonObject: any = { | ||
"countryName": "Switzerland", | ||
"cities": [ | ||
{ | ||
"id": 1, | ||
"name": "Basel", | ||
"founded": -200, | ||
"beautiful": true, | ||
{ | ||
"id": 1, | ||
"name": "Basel", | ||
"founded": -200, | ||
"beautiful": true, | ||
"data": 123, | ||
"keywords": ["Rhine", "River"] | ||
"keywords": ["Rhine", "River"] | ||
}, | ||
{ | ||
"id": 1, | ||
"name": "Zurich", | ||
"founded": 0, | ||
"beautiful": false, | ||
{ | ||
"id": 1, | ||
"name": "Zurich", | ||
"founded": 0, | ||
"beautiful": false, | ||
"data": "no", | ||
"keywords": ["Limmat", "Lake"] | ||
"keywords": ["Limmat", "Lake"] | ||
} | ||
] | ||
}; | ||
// Choose your settings | ||
@@ -229,3 +235,3 @@ // Check the detailed reference in the chapter "JsonConvert class properties and methods" | ||
jsonConvert.valueCheckingMode = ValueCheckingMode.DISALLOW_NULL; // never allow null | ||
// Map to the country class | ||
@@ -239,4 +245,5 @@ let country: Country; | ||
} | ||
} | ||
} | ||
``` | ||
Play around with the JSON to provocate exceptions when deserializing the object. | ||
@@ -246,4 +253,4 @@ | ||
Avoid circular depencencies on the classes that use `json2typescript`. | ||
Even if you don't have any errors in your IDE, `json2typescript` will not properly work in this case. | ||
Avoid circular dependencies on the classes that use `json2typescript`. Even if you don't have any errors in your | ||
IDE, `json2typescript` will not properly work in this case. | ||
@@ -256,4 +263,4 @@ --- | ||
Decorators should be used whenever you would like to map JSON with TypeScript data. | ||
As of now, you must not use more than one decorator per class or property. | ||
Decorators should be used whenever you would like to map JSON with TypeScript data. As of now, you must not use more | ||
than one decorator per class or property. | ||
@@ -269,4 +276,3 @@ ### Class decorators | ||
> Warning: The class decorator uses the parameter to identify the class. | ||
Please use a unique identifier for each class in your project, for example simply the name of the class. | ||
> Warning: The class decorator uses the parameter to identify the class. Please use a unique identifier for each class in your project, for example simply the name of the class. | ||
@@ -279,16 +285,33 @@ > Tip: Make sure you import `JsonObject` from `json2typescript`. | ||
> Note: This class identifier may be used for automatic instantiation when enabling the discriminator feature. | ||
### Property decorators | ||
Property decorators are a vital part for type checking. It is important that the type in the decorator matches the TypeScript type. | ||
Property decorators are a vital part for type checking. It is important that the type in the decorator matches the | ||
TypeScript type. | ||
For class properties to be visible to the mapper they **must be initialized**, otherwise they are ignored. | ||
They can be initialized using any (valid) value or `undefined`. | ||
See the example below for better understanding: | ||
```typescript | ||
@JsonObject("User") | ||
export class User { | ||
@JsonProperty("jsonPropertyName", String, false) | ||
name: string = undefined; | ||
// A correct example | ||
@JsonProperty("name", String, false) | ||
name: string = ""; | ||
// An incorrect example | ||
@JsonProperty("alias", string, false) // Wrong type: Must use String instead. | ||
alias: string = ""; | ||
// An incorrect example | ||
@JsonProperty("expertise", String, false) | ||
expertise: string; // No initialization: Property will be ignored without visible exception | ||
} | ||
``` | ||
Important note: You must assign any (valid) value or `undefined` to your property at | ||
initialization, otherwise our mapper does **not** work and will simply ignore the property. | ||
> **Important note**: You must assign any (valid) value or `undefined` to your property at initialization, otherwise our mapper does **not** work and will simply ignore the property. Assigning no value is not the same as assigning `undefined` in context of `json2typescript`. Non-initialized properties will not trigger any exception, as **they are invisible to the mapper**. | ||
@@ -299,17 +322,16 @@ > Tip: Make sure you import `JsonObject` and `JsonProperty` from `json2typescript`. | ||
The first parameter of `@JsonProperty` is the JSON object property name. | ||
It happens that the property names given by the server are very ugly. | ||
Here you can map any json property name to the `User` property `name`. | ||
In our case, `json["jsonPropertyName"]` gets mapped to `user.name`. | ||
The first parameter of `@JsonProperty` is the JSON object property name. It happens that the property names given by the | ||
server are very ugly. Here you can map any json property name to the `User` property `name`. In our | ||
case, `json["jsonPropertyName"]` gets mapped to `user.name`. | ||
#### Second parameter (optional): conversionOption | ||
The second parameter of `@JsonProperty` describes what happens when doing the mapping between JSON and TypeScript objects. | ||
This parameter is optional; the default value is `Any` (which means no type check is done when the mapping happens). | ||
The second parameter of `@JsonProperty` describes what happens when doing the mapping between JSON and TypeScript | ||
objects. This parameter is optional; the default value is `Any` (which means no type check is done when the mapping | ||
happens). | ||
##### Use of expected type | ||
If you would like that `json2typescript` performs an automatic type | ||
check according to given TypeScript types, you can pass a type you | ||
expect. Follow the following guide when doing that: | ||
If you would like that `json2typescript` performs an automatic type check according to given TypeScript types, you can | ||
pass a type you expect. Follow the following guide when doing that: | ||
@@ -323,3 +345,3 @@ - Make sure you pass the class name and not an instance of the class. | ||
| Expected type | TypeScript type | | ||
| --- | :--- | | ||
| --- | --- | | ||
| String | string | | ||
@@ -337,5 +359,4 @@ | Number | number | | ||
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. | ||
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. | ||
@@ -345,7 +366,6 @@ ##### Adding a custom converter | ||
More advanced users may need to use custom converters. If you want | ||
`json2typescript` to use your custom converter, you need to follow these | ||
steps: | ||
`json2typescript` to use your custom converter, you need to follow these steps: | ||
- Write a converter class that implements `JsonCustomConvert<T>` where | ||
`<T>` is the type resulting in the TypeScript class. | ||
`<T>` is the type resulting in the TypeScript class. | ||
- Make sure you add the `@JsonConverter` decorator to this class (see next chapter how). | ||
@@ -362,40 +382,79 @@ - Pass your converter class as second param in the `@JsonProperty` decorator | ||
@JsonProperty("birthdate", DateConverter) | ||
birthdate: Date = undefined; | ||
birthdate: Date = new Date(); | ||
} | ||
``` | ||
#### Third parameter (optional): isOptional | ||
#### Third parameter (optional): convertingMode | ||
The third parameter of `@JsonProperty` determines whether the `jsonProperty` has to be present in the json. | ||
This parameter is optional; the default value is false. | ||
The third parameter of `@JsonProperty` determines how nullable property types should be serialized and deserialized. | ||
Nullable types are either missing (in JSON), undefined (in TypeScript) or null (both). This parameter is optional; the | ||
default value is `PropertyConvertingMode.MAP_NULLABLE`. | ||
By default, `JsonConvert` throws an exception if a decorated class property cannot be found in the given JSON when deserializing. | ||
If you set the third parameter to true, there is no exception when it is missing. | ||
The type is still checked as soon the property is present again. | ||
See also the property `propertyConvertingMode` of the `JsonConvert` instance. | ||
The same applies for the case when you try to serialize a TypeScript object to a JSON object. If the property is not defined in the class and optional, it will not be added to the JSON object. | ||
The values should be used as follows: | ||
> Tip: Some API's return null instead of omitting optional values. | ||
If you flag a property as optional, `json2typescript` will ignore (JSON) null values at deserialization and keep the default value of the property instead. | ||
This fact is particularly helpful if your project uses TypeScript `strictNullChecks` or/and disallows `null` values through the `valueCheckingMode` property in `json2typescript`. | ||
Furthermore, note that the instance property `ignoreRequiredCheck` – if set to true – overrides all `isOptional` values for all properties. | ||
- `PropertyConvertingMode.MAP_NULLABLE`: the mapper is applied, type is checked | ||
- `PropertyConvertingMode.IGNORE_NULLABLE`: the mapper is not applied if the property is missing, undefined or null; the | ||
property is not added to the result | ||
- `PropertyConvertingMode.PASS_NULLABLE`: the mapper is not applied if the property is missing, undefined or null; the | ||
property is added with its value to the result | ||
> Tip: Make sure you import the `ENUM` `PropertyConvertingMode` when assigning a value to this property. | ||
##### Handling null, undefined and absent values | ||
Be careful when handling special values as `null`, `undefined` and `absent` properties. | ||
By default, `json2typescript` throws an exception if a decorated class property cannot be found in the given JSON when | ||
deserializing. If you set the third parameter to `IGNORE_NULLABLE` or `PASS_NULLABLE`, there will be no exception when | ||
it is missing. The type of a property will only be checked if the property is present in the JSON and not `undefined` | ||
or `null`. | ||
The global setting of `valueCheckingMode` determines whether you want to allow `null` values for objects or properties. | ||
We recommend to use the most strict option and also set your `TypeScript` compiler to the strict mode. | ||
The following table explains the difference between the three property converting modes: | ||
| **ALLOW_NULL** | `serialize(null)` | `serialize(undefined)` | `deserialize(null)` | `deserialize(undefined)` | | ||
| --- | --- | --- | --- | --- | | ||
| `MAP_NULLABLE` | `null` | error | `null` | error | | ||
| `IGNORE_NULLABLE` | `undefined` (missing) | `undefined` (missing) | default value | default value | | ||
| `PASS_NULLABLE` | `null` | `undefined` (missing) | `null` | `undefined` | | ||
| | | ||
| **DISALLOW_NULL** | `serialize(null)` | `serialize(undefined)` | `deserialize(null)` | `deserialize(undefined)` | | ||
| `MAP_NULLABLE` | error | error | error | error | | ||
| `IGNORE_NULLABLE` | `undefined` (missing) | `undefined` (missing) | default value | default value | | ||
| `PASS_NULLABLE` | `null` | `undefined` (missing) | `null` | `undefined` | | ||
As shown in this table, a property with the default setting `MAP_NULLABLE` is never allowed to be `undefined` (or | ||
missing). The `valueCheckingMode` determines, whether `null` is allowed. | ||
> Tip: If you want `undefined` to be treated in the same way as `null` values, you may set the instance `mapUndefinedToNull` property to `true`. | ||
#### 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, 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 `Any` as expected type. You may also omit the second parameter of `@JsonProperty`. | ||
* If you don't know the type, you may use `Any` 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`). | ||
* 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. | ||
* 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. | ||
* For example, if we define `[String]` or the equivalent `[String, String]` no exception is thrown - even if the JSON | ||
gives us an empty array. | ||
@@ -406,5 +465,5 @@ > Tip: See the examples at the end of this document for advanced examples for nesting arrays. | ||
In some cases, you may need to make custom conversion between JSON objects and TypeScript objects. You can define custom converters like this: | ||
In some cases, you may need to make custom conversion between JSON objects and TypeScript objects. You can define custom | ||
converters like this: | ||
```typescript | ||
@@ -414,4 +473,5 @@ @JsonConverter | ||
serialize(date: Date): any { | ||
return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); | ||
return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); | ||
} | ||
deserialize(date: any): Date { | ||
@@ -425,5 +485,6 @@ return new Date(date); | ||
Assume that in your JSON you have a date in a standardized format, such as `2017-07-19 10:00:00`. You could use the custom converter class above to make sure it is stored as a real TypeScript `Date` in your class. For your property, you simply have use the `@JsonProperty` decorator as follows: | ||
Assume that in your JSON you have a date in a standardized format, such as `2017-07-19 10:00:00`. You could use the | ||
custom converter class above to make sure it is stored as a real TypeScript `Date` in your class. For your property, you | ||
simply have use the `@JsonProperty` decorator as follows: | ||
```typescript | ||
@@ -433,3 +494,3 @@ @JsonObject("User") | ||
@JsonProperty("date", DateConverter) | ||
date: Date = undefined; | ||
date: Date = new Date(); | ||
} | ||
@@ -440,4 +501,2 @@ ``` | ||
## JsonConvert class properties and methods | ||
@@ -451,5 +510,6 @@ | ||
Determines how the JsonConvert class instance should operate. | ||
Determines how the JsonConvert class instance should operate. | ||
You may assign three different values: | ||
- `OperationMode.DISABLE`: json2typescript will be disabled, no type checking or mapping is done | ||
@@ -461,9 +521,9 @@ - `OperationMode.ENABLE`: json2typescript is enabled, but only errors are logged | ||
In some cases, you might consider disabling `json2typescript` in production by setting the `OperationMode.DISABLE` flag. | ||
This only works in case you only use plain objects without functionality and no mapping. | ||
However, disabling `json2typescript` might give you a performance advantage in heavy projects. | ||
In some cases, you might consider disabling `json2typescript` in production by setting the `OperationMode.DISABLE` flag. | ||
This only works in case you only use plain objects without functionality and no mapping. However, | ||
disabling `json2typescript` might give you a performance advantage in heavy projects. | ||
In case you have issues to find bugs, you can enable additional logging by setting the `OperationMode.LOGGING` flag. | ||
Please note that every serializing and deserializing is heavily logged to the console and will make your application slower. | ||
Never use this flag in production. | ||
Please note that every serializing and deserializing is heavily logged to the console and will make your application | ||
slower. Never use this flag in production. | ||
@@ -476,4 +536,4 @@ > Tip: Make sure you import the `ENUM` `OperationMode` when assigning a value to this property. | ||
Determines which types are allowed to be null. | ||
You may assign three different values: | ||
Determines which types are allowed to be null in the deserialization. You may assign three different values: | ||
* `ValueCheckingMode.ALLOW_NULL`: All given values can be null | ||
@@ -483,10 +543,19 @@ * `ValueCheckingMode.ALLOW_OBJECT_NULL`: Objects can be null, but primitive types cannot be null | ||
The default is `ValueCheckingMode.ALLOW_OBJECT_NULL`. | ||
The default is `ValueCheckingMode.ALLOW_OBJECT_NULL`. | ||
> Tip: Make sure you import the `ENUM` `ValueCheckingMode` when assigning a value to this property. | ||
> Tip: The TypeScript documentation suggests to avoid null values. | ||
Compile your TypeScript code with `strictNullChecks=true` and set the `valueCheckingMode` to disallow null values. | ||
If your API returns `null` in some cases, simply mark these properties as optional in the corresponding `JsonProperty` decorator to avoid errors on runtime. | ||
> Tip: The TypeScript documentation suggests to avoid null values. Compile your TypeScript code with `strictNullChecks=true` and set the `valueCheckingMode` to disallow null values. If your API returns `null` in some cases, simply mark these properties as optional in the corresponding `JsonProperty` decorator to avoid errors on runtime. | ||
#### Map undefined to null | ||
`(number) JsonConvert.mapUndefinedToNull` | ||
Determines whether a missing or undefined property value should be considered as null or not. | ||
If true, a missing JSON value will be added and set as null before deserialization. For serialization, undefined values | ||
will be set to null before serialization. | ||
> Note: ValueCheckingMode and PropertyConvertingMode determine whether an error will be thrown during serialization or deserialization. | ||
#### Ignore primitive checks | ||
@@ -496,4 +565,4 @@ | ||
Determines whether primitive types should be checked. | ||
If true, it will be allowed to assign primitive to other primitive types. | ||
Determines whether primitive types should be checked. If true, it will be allowed to assign primitive to other primitive | ||
types. | ||
@@ -506,19 +575,57 @@ The default is `false`. | ||
Determines the rule of how JSON properties shall be matched with class properties during deserialization. | ||
You may assign the following two values: | ||
Determines the rule of how JSON properties shall be matched with class properties during deserialization. You may assign | ||
the following two values: | ||
* `PropertyMatchingRule.CASE_STRICT`: JSON properties need to match exactly the names in the decorators | ||
* `PropertyMatchingRule.CASE_INSENSITIVE`: JSON properties need to match names in the decorators, but names they are not case sensitive | ||
* `PropertyMatchingRule.CASE_INSENSITIVE`: JSON properties need to match names in the decorators, but names they are not | ||
case sensitive | ||
The default is `PropertyMatchingRule.CASE_STRICT`. | ||
#### Ignore required property checks | ||
#### Property converting mode | ||
`(bool) JsonConvert.ignoreRequiredCheck` | ||
`(number|undefined) JsonConvert.propertyConvertingMode` | ||
Determines whether the check for required properties should be ignored, making all mapped values optional, whether or not the isOptional property mapping parameter is set. | ||
If true, any missing properties (undefined) when serializing or deserializing will be ignored, as if they were marked optional. | ||
Note that properties explicitly set to null will be unaffected by this flag – they will be ignored if optional and included if not. | ||
Determines how nullable property types should be serialized and deserialized. Nullable types are either missing (in | ||
JSON), undefined (in TypeScript) or null (both). | ||
If the propertyConvertingMode has a non-undefined value, it overrides the individual settings of every property. See | ||
also the third parameter of the `@JsonProperty` decorator. | ||
The values should be used as follows: | ||
- `PropertyConvertingMode.MAP_NULLABLE`: the mapper is applied, type is checked | ||
- `PropertyConvertingMode.IGNORE_NULLABLE`: the mapper is not applied if the property is missing, undefined or null; the | ||
property is | ||
* not added to the result | ||
- `PropertyConvertingMode.PASS_NULLABLE`: the mapper is not applied if the property is missing, undefined or null; the | ||
property is | ||
* added with its value to the result | ||
The default is `PropertyMatchingRule.MAP_NULLABLE`. | ||
> Note: This property is usually only temporarily set and should be used with caution. | ||
> It replaces the deprecated property `ignoreRequiredCheck`. | ||
#### Use discriminator | ||
`(bool) JsonConvert.useDiscriminator` | ||
Determines if discriminators should be used. | ||
If this option is set to true, all registered classes will be serialized with an additional discriminator property (default: "$type"), which has the key of the class (given in the @JsonObject decorator) as value. | ||
When deserializing an object containing the discriminator property, json2typescript will attempt to automatically instantiate the correct type (by comparing the value of the discriminator property with the registered classes). | ||
The default is `false`. | ||
> Note: At the end of this document you may find an example on how to use the discriminator feature. | ||
#### Discriminator property name | ||
`(string) JsonConvert.discriminatorPropertyName` | ||
Defines the name of the discriminator property. | ||
The default is `"$type"`. | ||
### Public methods | ||
@@ -529,38 +636,78 @@ | ||
#### Serializing (TypeScript to JSON) | ||
`(any) serialize(data: any | any[])` | ||
`(any|any[]) serialize<T extends object, U extends object = {}>(data: T | T[], classReference?: { new(): U })` | ||
Tries to serialize a TypeScript object or array of objects to JSON. | ||
The first parameter must be a TypeScript object or array, the second parameter is the optional class reference. | ||
If you provide only one parameter, the class for serialization is inferred automatically. For example, if you | ||
call `jsonConvert.serialize(user)` where `user` is an instance of the class `User`, `json2typescript` will automatically | ||
use this class for serialization. | ||
By providing two parameters, it will override the class for serialization. For example, this allows you to | ||
call `jsonConvert.serialize(userObject, User)` where `userObject` is just a plain TypeScript `any` object. | ||
The returned value will be `any` object or an array of `any` objects. | ||
> Tip: The return value is not a string. In case you need a string as result, use `JSON.stringify()` after calling the serialize method. | ||
You may optionally provide a class constructor to use the `@JsonProperty` mappings defined for that class to serialize | ||
the data object(s), instead of mappings defined on the data class. Note that if the data is an array, the mappings from | ||
the constructor class are used for *all* elements in the array. If no constructor is provided, the mappings from the | ||
data object class are used to serialize the data object(s). | ||
> Tip: This feature is helpful if you need to serialize an object that was not created using a class constructor, or if you want to serialize a subclass with only the properties of the superclass. | ||
#### Deserializing (JSON to TypeScript) | ||
`(T | T[]) deserialize(json: any, classReference: { new(): T | T[] })` | ||
`(T | T[]) deserialize<T extends object>(json: any, classReference: { new(): T })` | ||
Tries to deserialize given JSON to a TypeScript object or array of objects. | ||
> Tip: The param `json` must not be a string, but an `object` or an `array`. Use `JSON.parse()` before applying the deserialize method in case you have a json string. | ||
The first parameter must be a Typescript object or array, the second parameter is the class reference. | ||
The returned value will be an instance or an array of instances of the given class reference. | ||
> Tip: The param `json` must not be a string, but an `object` or an `array`. Use `JSON.parse()` before applying the deserialize method in case you have a json string. | ||
#### Registering and unregistering classes | ||
`void registerClasses(...classReferences: { new(): any }[])` | ||
Registers a list of classes to be used in the discriminator feature. | ||
`void ungisterClasses(...classReferences: { new(): any }[])` | ||
Unregisters a list of classes from the discriminator feature. | ||
`void unregisterAllClasses()` | ||
Unregisters all classes from the discriminator feature. | ||
> Note: You only need to register and unregister classes if you use the discriminator feature. Otherwise, these methods are without any effect. | ||
#### Other methods | ||
The methods `serialize()` and `deserialize()` will automatically detect the dimension of your param (either object or array). | ||
In case you would like to force `json2typescript` to use a specific way, you can use the following methods instead: | ||
- `(any) serializeObject(instance: any)` | ||
- `(any[]) serializeArray(instanceArray: any[])` | ||
- `(T) deserializeObject(jsonObject: any, classReference: { new(): T })` | ||
- `(T[]) deserializeArray(jsonArray: any[], classReference: { new(): T })` | ||
The methods `serialize()` and `deserialize()` will automatically detect the dimension of your param (either object or | ||
array). In case you would like to force `json2typescript` to use a specific way, you can use the following methods | ||
instead: | ||
- `(any) serializeObject<T extends object, U extends object = {}>(data: T, classReference?: { new(): U })` | ||
- `(any[]) serializeArray<T extends object, U extends object = {}>(dataArray: T[], classReference?: { new(): U })` | ||
- `(T) deserializeObject<T extends object>(jsonObject: any, classReference: { new(): T })` | ||
- `(T[]) deserializeArray<T extends object>(jsonArray: any[], classReference: { new(): T })` | ||
--- | ||
# Further examples | ||
# Advanced strategies | ||
In case you don't have enough complex examples yet, you may find some more in this section. | ||
In this section you will find additional examples. | ||
## 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: | ||
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: | ||
@@ -573,6 +720,12 @@ ### 1) Nested arrays with same type | ||
{ | ||
"jsonKeyOfWeirdKeywords": [ | ||
["Hello", "World"], | ||
["Bye", "Earth"] | ||
"jsonKeyOfWeirdKeywords": [ | ||
[ | ||
"Hello", | ||
"World" | ||
], | ||
[ | ||
"Bye", | ||
"Earth" | ||
] | ||
] | ||
} | ||
@@ -587,3 +740,3 @@ ``` | ||
@JsonProperty("jsonKeyOfWeirdKeywords", [[String, String], [String, String]]) | ||
keywords: any = undefined; | ||
keywords: (string[])[] = []; | ||
} | ||
@@ -600,6 +753,9 @@ ``` | ||
{ | ||
"jsonKeyOfWeirdKeywords": [ | ||
["FC", "Basel"], | ||
1893 | ||
] | ||
"jsonKeyOfWeirdKeywords": [ | ||
[ | ||
"FC", | ||
"Basel" | ||
], | ||
1893 | ||
] | ||
} | ||
@@ -614,3 +770,3 @@ ``` | ||
@JsonProperty("jsonKeyOfWeirdKeywords", [[String, String], Number]) | ||
keywords: any = undefined; | ||
keywords: (string[] | number)[] = []; | ||
} | ||
@@ -621,11 +777,75 @@ ``` | ||
## Automatic instantiation using the discriminator feature | ||
If your server adds a discriminator property to every JSON object, `json2typescript` is able to automatically instantiate objects. | ||
First, set up the discriminator feature for a class, for example | ||
```typescript | ||
@JsonObject("app.example.User") | ||
export class User { | ||
@JsonProperty("name", String) | ||
name: string = ""; | ||
} | ||
``` | ||
Now, set up a `JsonConvert` to enable the discriminator feature and activate it for the classes you like: | ||
```typescript | ||
// Set up json convert | ||
let jsonConvert: JsonConvert = new JsonConvert(); | ||
jsonConvert.useDiscriminator = true; // enable the discriminator | ||
jsonConvert.discriminatorPropertyName = "$type"; // this is the property name | ||
jsonConvert.registerClasses(User); // register all classes | ||
// Assume the following JSON object coming from your server | ||
const jsonObject: any = { | ||
"name": "Walter", | ||
"$type": "app.example.User" // the value of $type matches the @JsonObject decorator above | ||
} | ||
// This is how you would traditionally map an object | ||
// But we have enabled the discriminator functionality and registered the User class | ||
// In that case, the second parameter (User) here is ignored | ||
const user1: User = jsonConvert.deserialize(jsonObject, User); | ||
// But now you may automatically map it thanks to the $type property | ||
const user2: User = jsonConvert.deserialize<User>(jsonObject); | ||
``` | ||
> Note: This feature is particularly useful when doing dynamic mapping. | ||
> Otherwise, you just may provide the type yourself (as done above with `user1`) and disable the discriminator feature. | ||
A real-world example for the discriminator feature is the mapping of child classes. | ||
Assume that you might have two classes `AdminUser` and `NormalUser` that inherit from `User`. | ||
The web client sometimes cannot know the type in advance. | ||
If you use the discriminator feature, the server can define the type in the JSON and `json2typescript` will properly instantiate the desired class. | ||
This means, your property can be safely declared in TypeScript as union type of `AdminUser | NormalUser` instead of `User`. | ||
> Warning: If you enable the discriminator feature and try to deserialize a JSON object to a registered class instance, the second parameter of the `deserialize` methods is always ignored. | ||
--- | ||
# Tools | ||
## Class decorator generator | ||
Since version 1.4, `json2typescript` requires the `@JsonObject("ClassName")` decorator in front of the TypeScript class | ||
definition. GitHub user `tlmurphy` created a Python script that automatically generates the decorator with the original | ||
class name as parameter. | ||
More: https://gist.github.com/tlmurphy/71b58c71e594899120da365159d7d40d | ||
--- | ||
# Contributors | ||
This NPM package was originally created in 2016 by **Andreas Aeschlimann**, software architect at his own company (**AppVision GmbH**) and scientific researcher at the **Digital Humanities Lab** (**University of Basel**). | ||
This NPM package was originally created in 2016 by **Andreas Aeschlimann**, founder of and software architect at **AppVision GmbH**. | ||
## Special thanks | ||
You are welcome to report issues and discuss enhancements to make this package even more useful. | ||
Thanks for the input and all the pull requests from the community! | ||
You are welcome to report issues and discuss enhancements to make this package even more useful. Thanks for the input | ||
and all the pull requests from the community! |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
301178
45
4467
805
1
1