Repository: asyncapi/modelina
Pull request #806 (2022-07-08 22:03:05)

chore: rewrite TypeScript generator tests
**Description**
This PR adapts the generator tests for TypeScript

**Todo**
- [x] Update snapshots
- [x] Fix property and enum duplicate properties constrain
- [x] Fix EnumConstrainer test
- [x] Fix PropertyKeyConstrainer tests
- [x] Fix preset tests
- [x] fix generator test
- [x] fix renderer test

Blocked by https://github.com/asyncapi/modelina/pull/808

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=806)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [10 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=806)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=806)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=806)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=806)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=806&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=806&metric=duplicated_lines_density&view=list) No Duplication information


Samridhi-98: /rtm

Patch:
diff --git a/examples/generate-go-enums/__snapshots__/index.spec.ts.snap b/examples/generate-go-enums/__snapshots__/index.spec.ts.snap
index ad0ff99c..63a132b1 100644
--- a/examples/generate-go-enums/__snapshots__/index.spec.ts.snap
+++ b/examples/generate-go-enums/__snapshots__/index.spec.ts.snap
@@ -2,37 +2,70 @@
 
 exports[`Should be able to render Go Enums and should log expected output to console 1`] = `
 Array [
-  "// Cities represents an enum of string.
-type Cities string
-
-const (
-  CitiesLondon Cities = \\"London\\"
-  CitiesRome = \\"Rome\\"
-  CitiesBrussels = \\"Brussels\\"
-)",
+  "// Root represents a Root model.
+type Root struct {
+  Cities *Cities
+  Options *Options
+}",
 ]
 `;
 
 exports[`Should be able to render Go Enums and should log expected output to console 2`] = `
 Array [
-  "// ClickOptions represents an enum of string.
-type ClickOptions string
+  "// Cities represents an enum of Cities.
+type Cities uint
 
 const (
-  ClickOptionsClickAndPlay ClickOptions = \\"click_and_play\\"
-  ClickOptionsClickPay = \\"click&pay\\"
-)",
+  CitiesLondon Cities = iota
+  CitiesRome
+  CitiesBrussels
+)
+
+// Value returns the value of the enum.
+func (op Cities) Value() any {
+	if op >= Cities(len(CitiesValues)) {
+		return nil
+	}
+	return CitiesValues[op]
+}
+
+var CitiesValues = []any{\\"London\\",\\"Rome\\",\\"Brussels\\"}
+var ValuesToCities = map[any]Cities{
+  CitiesValues[CitiesLondon]: CitiesLondon,
+  CitiesValues[CitiesRome]: CitiesRome,
+  CitiesValues[CitiesBrussels]: CitiesBrussels,
+}
+",
 ]
 `;
 
 exports[`Should be able to render Go Enums and should log expected output to console 3`] = `
 Array [
-  "// Options represents an enum of int.
-type Options int
+  "// Options represents an enum of Options.
+type Options uint
 
 const (
-  OptionsFirstOption Options = iota
-  OptionsSecondOption
-)",
+  OptionsNumber_123 Options = iota
+  OptionsNumber_213
+  OptionsTrue
+  OptionsRun
+)
+
+// Value returns the value of the enum.
+func (op Options) Value() any {
+	if op >= Options(len(OptionsValues)) {
+		return nil
+	}
+	return OptionsValues[op]
+}
+
+var OptionsValues = []any{123,213,true,\\"Run\\"}
+var ValuesToOptions = map[any]Options{
+  OptionsValues[OptionsNumber_123]: OptionsNumber_123,
+  OptionsValues[OptionsNumber_213]: OptionsNumber_213,
+  OptionsValues[OptionsTrue]: OptionsTrue,
+  OptionsValues[OptionsRun]: OptionsRun,
+}
+",
 ]
 `;
diff --git a/examples/generate-go-enums/index.spec.ts b/examples/generate-go-enums/index.spec.ts
index 606842a9..c7e70d5c 100644
--- a/examples/generate-go-enums/index.spec.ts
+++ b/examples/generate-go-enums/index.spec.ts
@@ -7,10 +7,10 @@ describe('Should be able to render Go Enums', () => {
   });
   test('and should log expected output to console', async () => {
     await generate();
-    //Generate is called 2x, so even though we expect 4 model (root and three different enums type), we double it
-    expect(spy.mock.calls.length).toEqual(8);
+    //Generate is called 2x, so even though we expect 3 model (root and three different enums type), we double it
+    expect(spy.mock.calls.length).toEqual(6);
+    expect(spy.mock.calls[0]).toMatchSnapshot();
     expect(spy.mock.calls[1]).toMatchSnapshot();
     expect(spy.mock.calls[2]).toMatchSnapshot();
-    expect(spy.mock.calls[3]).toMatchSnapshot();
   });
 });
diff --git a/examples/generate-go-enums/index.ts b/examples/generate-go-enums/index.ts
index 6e09f7f2..99c44dda 100644
--- a/examples/generate-go-enums/index.ts
+++ b/examples/generate-go-enums/index.ts
@@ -11,15 +11,10 @@ const jsonSchemaDraft7 = {
       type: 'string',
       enum: ['London', 'Rome', 'Brussels'],
     },
-    click_options: {
-      $id: 'click_options',
-      type: 'string',
-      enum: ['click_and_play', 'click&pay'],
-    },
     options: {
       $id: 'options',
-      type: 'integer',
-      enum: ['first_option', 'second_option'],
+      type: ['integer', 'boolean', 'string'],
+      enum: [123, 213, true, 'Run'],
     },
   }
 };
diff --git a/examples/typescript-enum-type/__snapshots__/index.spec.ts.snap b/examples/typescript-enum-type/__snapshots__/index.spec.ts.snap
index e624a619..664326f9 100644
--- a/examples/typescript-enum-type/__snapshots__/index.spec.ts.snap
+++ b/examples/typescript-enum-type/__snapshots__/index.spec.ts.snap
@@ -14,7 +14,7 @@ class Root {
   get event(): Event | undefined { return this._event; }
   set event(event: Event | undefined) { this._event = event; }
 }
-type Event = \\"ping\\" | \\"pong\\";
+type Event = Event;
 Generator output with Enum:
 class Root {
   private _event?: Event;
diff --git a/examples/typescript-generate-comments/__snapshots__/index.spec.ts.snap b/examples/typescript-generate-comments/__snapshots__/index.spec.ts.snap
index bfaf196e..620a07f8 100644
--- a/examples/typescript-generate-comments/__snapshots__/index.spec.ts.snap
+++ b/examples/typescript-generate-comments/__snapshots__/index.spec.ts.snap
@@ -13,8 +13,11 @@ interface Test {
    * @example Example
    */
   numberProp?: number;
+  /**
+   * @example Example 1, Example 2
+   */
   objectProp?: NestedTest;
-  additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  additionalProperties?: Map<string, any>;
 }",
   ],
   Array [
@@ -23,7 +26,7 @@ interface Test {
  */
 interface NestedTest {
   stringProp?: string;
-  additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  additionalProperties?: Map<string, any>;
 }",
   ],
   Array [
@@ -37,8 +40,11 @@ interface Test {
    * @example Example
    */
   numberProp?: number;
+  /**
+   * @example Example 1, Example 2
+   */
   objectProp?: NestedTest;
-  additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  additionalProperties?: Map<string, any>;
 }",
   ],
   Array [
@@ -47,7 +53,7 @@ interface Test {
  */
 interface NestedTest {
   stringProp?: string;
-  additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  additionalProperties?: Map<string, any>;
 }",
   ],
 ]
diff --git a/examples/typescript-generate-marshalling/__snapshots__/index.spec.ts.snap b/examples/typescript-generate-marshalling/__snapshots__/index.spec.ts.snap
index af7b5b89..500812ad 100644
--- a/examples/typescript-generate-marshalling/__snapshots__/index.spec.ts.snap
+++ b/examples/typescript-generate-marshalling/__snapshots__/index.spec.ts.snap
@@ -19,8 +19,7 @@ Array [
     if(this.email !== undefined) {
       json += \`\\"email\\": \${typeof this.email === 'number' || typeof this.email === 'boolean' ? this.email : JSON.stringify(this.email)},\`; 
     }
-  
-  
+
 
     //Remove potential last comma 
     return \`\${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}\`;
@@ -34,13 +33,8 @@ Array [
       instance.email = obj[\\"email\\"];
     }
 
-    //Not part of core properties
-  
-  
-    for (const [key, value] of Object.entries(obj).filter((([key,]) => {return ![\\"email\\"].includes(key);}))) {
-    
-    
-    }
+
+
     return instance;
   }
 }",
diff --git a/examples/typescript-use-cjs/__snapshots__/index.spec.ts.snap b/examples/typescript-use-cjs/__snapshots__/index.spec.ts.snap
index 6945ed97..700591b3 100644
--- a/examples/typescript-use-cjs/__snapshots__/index.spec.ts.snap
+++ b/examples/typescript-use-cjs/__snapshots__/index.spec.ts.snap
@@ -3,7 +3,6 @@
 exports[`Should be able to render models to ESM module system and should log expected output to console 1`] = `
 Array [
   "
-
 class Person {
   private _email?: string;
 
@@ -23,7 +22,6 @@ module.exports = Person;",
 exports[`Should be able to render models to ESM module system and should log expected output to console 2`] = `
 Array [
   "const Person = require('./Person');
-
 class Root {
   private _person?: Person;
 
diff --git a/examples/typescript-use-esm/__snapshots__/index.spec.ts.snap b/examples/typescript-use-esm/__snapshots__/index.spec.ts.snap
index a8f1b846..33aaa27d 100644
--- a/examples/typescript-use-esm/__snapshots__/index.spec.ts.snap
+++ b/examples/typescript-use-esm/__snapshots__/index.spec.ts.snap
@@ -3,7 +3,6 @@
 exports[`Should be able to render models to ESM module system and should log expected output to console 1`] = `
 Array [
   "
-
 class Person {
   private _email?: string;
 
@@ -24,7 +23,6 @@ export default Person;
 exports[`Should be able to render models to ESM module system and should log expected output to console 2`] = `
 Array [
   "import Person from './Person';
-
 class Root {
   private _person?: Person;
 
diff --git a/src/generators/go/GoConstrainer.ts b/src/generators/go/GoConstrainer.ts
index e4b471bb..87fad716 100644
--- a/src/generators/go/GoConstrainer.ts
+++ b/src/generators/go/GoConstrainer.ts
@@ -1,4 +1,4 @@
-import { TypeMapping } from '../../helpers';
+import { Constraints, TypeMapping } from '../../helpers';
 import { defaultEnumKeyConstraints, defaultEnumValueConstraints } from './constrainer/EnumConstrainer';
 import { defaultModelNameConstraints } from './constrainer/ModelNameConstrainer';
 import { defaultPropertyKeyConstraints } from './constrainer/PropertyKeyConstrainer';
@@ -9,7 +9,7 @@ export const GoDefaultTypeMapping: TypeMapping<GoOptions> = {
     return constrainedModel.name;
   },
   Reference ({constrainedModel}): string {
-    return constrainedModel.name;
+    return `${constrainedModel.name}`;
   },
   Any (): string {
     return 'interface{}';
@@ -27,7 +27,7 @@ export const GoDefaultTypeMapping: TypeMapping<GoOptions> = {
     return 'bool';
   },
   Tuple (): string {
-    //Because Java have no notion of tuples (and no custom implementation), we have to render it as a list of any value.
+    //Because Go have no notion of tuples (and no custom implementation), we have to render it as a list of any value.
     return '[]interface{}';
   },
   Array ({constrainedModel}): string {
@@ -37,7 +37,7 @@ export const GoDefaultTypeMapping: TypeMapping<GoOptions> = {
     return constrainedModel.name;
   },
   Union (): string {
-    //Because Java have no notion of unions (and no custom implementation), we have to render it as any value.
+    //Because Go have no notion of unions (and no custom implementation), we have to render it as any value.
     return 'interface{}';
   },
   Dictionary ({constrainedModel}): string {
@@ -45,7 +45,7 @@ export const GoDefaultTypeMapping: TypeMapping<GoOptions> = {
   }
 };
 
-export const GoDefaultConstraints = {
+export const GoDefaultConstraints: Constraints = {
   enumKey: defaultEnumKeyConstraints(),
   enumValue: defaultEnumValueConstraints(),
   modelName: defaultModelNameConstraints(),
diff --git a/src/generators/go/constrainer/EnumConstrainer.ts b/src/generators/go/constrainer/EnumConstrainer.ts
index ce4e03c7..05ed8068 100644
--- a/src/generators/go/constrainer/EnumConstrainer.ts
+++ b/src/generators/go/constrainer/EnumConstrainer.ts
@@ -6,7 +6,13 @@ import { isReservedGoKeyword } from '../Constants';
 export type ModelEnumKeyConstraints = {
   NO_SPECIAL_CHAR: (value: string) => string;
   NO_NUMBER_START_CHAR: (value: string) => string;
-  NO_DUPLICATE_KEYS: (constrainedEnumModel: ConstrainedEnumModel, enumModel: EnumModel, value: string, namingFormatter: (value: string) => string) => string;
+  NO_DUPLICATE_KEYS: (constrainedEnumModel: ConstrainedEnumModel, 
+    enumModel: EnumModel, 
+    newEnumKey: string,
+    namingFormatter: (value: string) => string,
+    enumKeyToCheck: string,
+    onNameChange: () => string,
+    onNameChangeToCheck: () => string) => string;
   NO_EMPTY_VALUE: (value: string) => string;
   NAMING_FORMATTER: (value: string) => string;
   NO_RESERVED_KEYWORDS: (value: string) => string;
@@ -20,7 +26,7 @@ export const DefaultEnumKeyConstraints: ModelEnumKeyConstraints = {
   NO_NUMBER_START_CHAR,
   NO_DUPLICATE_KEYS: NO_DUPLICATE_ENUM_KEYS,
   NO_EMPTY_VALUE,
-  NAMING_FORMATTER: FormatHelpers.toConstantCase,
+  NAMING_FORMATTER: FormatHelpers.toPascalCase,
   NO_RESERVED_KEYWORDS: (value: string) => {
     return NO_RESERVED_KEYWORDS(value, isReservedGoKeyword); 
   }
@@ -35,14 +41,39 @@ export function defaultEnumKeyConstraints(customConstraints?: Partial<ModelEnumK
     constrainedEnumKey = constraints.NO_NUMBER_START_CHAR(constrainedEnumKey);
     constrainedEnumKey = constraints.NO_EMPTY_VALUE(constrainedEnumKey);
     constrainedEnumKey = constraints.NO_RESERVED_KEYWORDS(constrainedEnumKey);
+    //If the enum key has been manipulated, lets make sure it don't clash with existing keys
+    if (constrainedEnumKey !== enumKey) {
+      //Must check against the enum key with the constrained enum model name
+      constrainedEnumKey = constraints.NO_DUPLICATE_KEYS(
+        constrainedEnumModel, 
+        enumModel, 
+        constrainedEnumKey, 
+        constraints.NAMING_FORMATTER,
+        `${constrainedEnumModel.name}_${constrainedEnumKey}`, 
+        () => {
+          return `reserved_${constrainedEnumKey}`;
+        }, () => {
+          return `${constrainedEnumModel.name}_reserved_${constrainedEnumKey}`;
+        });
+    }
+    constrainedEnumKey = `${constrainedEnumModel.name}_${constrainedEnumKey}`;
     constrainedEnumKey = constraints.NAMING_FORMATTER(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_DUPLICATE_KEYS(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER);
     return constrainedEnumKey;
   };
 }
 
 export function defaultEnumValueConstraints(): EnumValueConstraint {
   return ({enumValue}) => {
-    return `"${enumValue}"`;
+    let constrainedEnumValue: any = JSON.stringify(enumValue);
+    switch (typeof enumValue) {
+    case 'string':
+      constrainedEnumValue = `"${enumValue}"`;
+      break;
+    case 'number':
+    case 'bigint':
+      constrainedEnumValue = enumValue;
+      break;
+    }
+    return constrainedEnumValue;
   };
 }
diff --git a/src/generators/go/constrainer/PropertyKeyConstrainer.ts b/src/generators/go/constrainer/PropertyKeyConstrainer.ts
index d750e78d..1dc23211 100644
--- a/src/generators/go/constrainer/PropertyKeyConstrainer.ts
+++ b/src/generators/go/constrainer/PropertyKeyConstrainer.ts
@@ -37,8 +37,11 @@ export function defaultPropertyKeyConstraints(customConstraints?: Partial<Proper
     constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
     constrainedPropertyKey = constraints.NO_EMPTY_VALUE(constrainedPropertyKey);
     constrainedPropertyKey = constraints.NO_RESERVED_KEYWORDS(constrainedPropertyKey);
+    //If the property name has been manipulated, lets make sure it don't clash with existing properties
+    if (constrainedPropertyKey !== objectPropertyModel.propertyName) {
+      constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER);
+    }
     constrainedPropertyKey = constraints.NAMING_FORMATTER(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER);
     return constrainedPropertyKey;
   };
 }
diff --git a/src/generators/go/renderers/EnumRenderer.ts b/src/generators/go/renderers/EnumRenderer.ts
index dcc3bddd..5c8f6712 100644
--- a/src/generators/go/renderers/EnumRenderer.ts
+++ b/src/generators/go/renderers/EnumRenderer.ts
@@ -1,31 +1,47 @@
 import { GoRenderer } from '../GoRenderer';
 import { ConstrainedEnumModel } from '../../../models';
-import { FormatHelpers } from '../../../helpers';
 import { EnumPresetType } from '../GoPreset';
 import { GoOptions } from '../GoGenerator';
 
 /**
  * Renderer for Go's `enum` type
  * 
+ * This renderer is a generic solution that works for all types of enum values.
+ * This is also why you wont see `type MyEnum string´ even if possible.
+ * 
  * @extends GoRenderer
  */
 export class EnumRenderer extends GoRenderer<ConstrainedEnumModel> {
   public defaultSelf(): string {
     const doc = this.renderCommentForEnumType(this.model.name, this.model.type);
-    // eslint-disable-next-line sonarjs/no-duplicate-string
-    if (this.model.type === 'interface{}') {
-      return `${doc}
-type ${this.model.name} ${this.model.type}`;
-    }
-
-    const enumValues = this.renderConstValuesForEnumType(this.model.name, this.model.type, <string[]> this.model.values.map((enumValue) => enumValue.value));
+    const enumValues = this.renderConstValuesForEnumType();
+    const temp = this.model.values.map((value) => {
+      return `${this.model.name}Values[${value.key}]: ${value.key},`;
+    });
+    const values = this.model.values.map((value) => {
+      return value.value;
+    }).join(',');
 
     return `${doc}
-type ${this.model.name} ${this.model.type}
+type ${this.model.name} uint
 
 const (
 ${this.indent(this.renderBlock(enumValues))}
-)`;
+)
+
+// Value returns the value of the enum.
+func (op ${this.model.name}) Value() any {
+	if op >= ${this.model.name}(len(${this.model.name}Values)) {
+		return nil
+	}
+	return ${this.model.name}Values[op]
+}
+
+var ${this.model.name}Values = []any{${values}}
+var ValuesTo${this.model.name} = map[any]${this.model.name}{
+${this.indent(this.renderBlock(temp))}
+}
+`;
   }
 
   renderCommentForEnumType(name: string, type: string): string {
@@ -33,28 +49,21 @@ ${this.indent(this.renderBlock(enumValues))}
     return this.renderComments(`${name} represents an enum of ${globalType}.`);
   }
 
-  renderConstValuesForEnumType(typeName: string, innerType: string, values: string[]): string[] {
-    const firstName = typeName.concat(FormatHelpers.upperFirst(FormatHelpers.toCamelCase(values[0].toString())));
-
-    let enumValues = [innerType === 'string' ? `${firstName} ${typeName} = "${values[0]}"` : `${firstName} ${typeName} = iota`];
-
-    for (const value of values.slice(1)) {
-      const name = typeName.concat(FormatHelpers.upperFirst(FormatHelpers.toCamelCase(value)));
-
-      if (innerType === 'string') {
-        enumValues = enumValues.concat(`${name} = "${value}"`);
+  renderConstValuesForEnumType(): string[] {
+    return this.model.values.map((enumValue, index) => {
+      if (index === 0) {
+        return `${enumValue.key} ${this.model.name} = iota`;
       }
-      if (innerType === 'int') {
-        enumValues = enumValues.concat(`${name}`);
+      if (typeof enumValue.value === 'string') {
+        return enumValue.key;
       }
-    }
-
-    return enumValues;
+      return enumValue.key;
+    });
   }
 }
 
 export const GO_DEFAULT_ENUM_PRESET: EnumPresetType<GoOptions> = {
   self({ renderer }) {
     return renderer.defaultSelf();
-  },
+  }
 };
diff --git a/src/generators/go/renderers/StructRenderer.ts b/src/generators/go/renderers/StructRenderer.ts
index 6688a349..23be6dd9 100644
--- a/src/generators/go/renderers/StructRenderer.ts
+++ b/src/generators/go/renderers/StructRenderer.ts
@@ -1,6 +1,6 @@
 import { GoRenderer } from '../GoRenderer';
 import { StructPresetType } from '../GoPreset';
-import { ConstrainedObjectModel, ConstrainedObjectPropertyModel } from 'models';
+import { ConstrainedObjectModel, ConstrainedObjectPropertyModel, ConstrainedReferenceModel } from '../../../models';
 import { GoOptions } from '../GoGenerator';
 
 /**
@@ -44,6 +44,10 @@ export const GO_DEFAULT_STRUCT_PRESET: StructPresetType<GoOptions> = {
     return renderer.defaultSelf();
   },
   field({ field }) {
-    return `${ field } ${ field.property.type }`;
+    let fieldType = field.property.type;
+    if (field.property instanceof ConstrainedReferenceModel) {
+      fieldType = `*${fieldType}`; 
+    }
+    return `${ field.propertyName } ${ fieldType }`;
   },
 };
diff --git a/src/generators/typescript/TypeScriptConstrainer.ts b/src/generators/typescript/TypeScriptConstrainer.ts
index 3c841e58..378ca22c 100644
--- a/src/generators/typescript/TypeScriptConstrainer.ts
+++ b/src/generators/typescript/TypeScriptConstrainer.ts
@@ -46,7 +46,7 @@ export const TypeScriptDefaultTypeMapping: TypeMapping<TypeScriptOptions> = {
     });
     return unionTypes.join(' | ');
   },
-  Dictionary ({constrainedModel}): string {
+  Dictionary ({constrainedModel, options}): string {
     let keyType;    
     //There is some restrictions on what can be used as keys for dictionaries.
     if (constrainedModel.key instanceof ConstrainedUnionModel) {
@@ -55,8 +55,15 @@ export const TypeScriptDefaultTypeMapping: TypeMapping<TypeScriptOptions> = {
     } else {
       keyType = constrainedModel.key.type;
     }
-
-    return `{ [name: ${keyType}]: ${constrainedModel.value.type} }`;
+    switch (options.mapType) {
+    case 'indexedObject':
+      return `{ [name: ${keyType}]: ${constrainedModel.value.type} }`;
+    case 'record':
+      return `Record<${keyType}, ${constrainedModel.value.type}>`;
+    default:
+    case 'map':
+      return `Map<${keyType}, ${constrainedModel.value.type}>`;
+    }
   }
 };
 
diff --git a/src/generators/typescript/TypeScriptGenerator.ts b/src/generators/typescript/TypeScriptGenerator.ts
index a3b63082..95fb1431 100644
--- a/src/generators/typescript/TypeScriptGenerator.ts
+++ b/src/generators/typescript/TypeScriptGenerator.ts
@@ -4,24 +4,27 @@ import {
   defaultGeneratorOptions
 } from '../AbstractGenerator';
 import { ConstrainedEnumModel, ConstrainedMetaModel, ConstrainedObjectModel, InputMetaModel, MetaModel, RenderOutput } from '../../models';
-import { constrainMetaModel, Constraints, split, TypeMapping } from '../../helpers';
+import { constrainMetaModel, Constraints, split, TypeMapping, hasPreset } from '../../helpers';
 import { TypeScriptPreset, TS_DEFAULT_PRESET } from './TypeScriptPreset';
 import { ClassRenderer } from './renderers/ClassRenderer';
 import { InterfaceRenderer } from './renderers/InterfaceRenderer';
 import { EnumRenderer } from './renderers/EnumRenderer';
 import { TypeRenderer } from './renderers/TypeRenderer';
 import { TypeScriptDefaultConstraints, TypeScriptDefaultTypeMapping } from './TypeScriptConstrainer';
+import { TS_EXPORT_KEYWORD_PRESET } from './presets';
 
 export interface TypeScriptOptions extends CommonGeneratorOptions<TypeScriptPreset> {
   renderTypes: boolean;
   modelType: 'class' | 'interface';
   enumType: 'enum' | 'union';
+  mapType: 'indexedObject' | 'map' | 'record';
   typeMapping: TypeMapping<TypeScriptOptions>;
   constraints: Constraints;
 }
 
 export interface TypeScriptRenderCompleteModelOptions {
   moduleSystem?: 'ESM' | 'CJS';
+  exportType?: 'default' | 'named';
 }
 
 /**
@@ -33,6 +36,7 @@ export class TypeScriptGenerator extends AbstractGenerator<TypeScriptOptions,Typ
     renderTypes: true,
     modelType: 'class',
     enumType: 'enum',
+    mapType: 'map',
     defaultPreset: TS_DEFAULT_PRESET,
     typeMapping: TypeScriptDefaultTypeMapping,
     constraints: TypeScriptDefaultConstraints
@@ -73,29 +77,48 @@ export class TypeScriptGenerator extends AbstractGenerator<TypeScriptOptions,Typ
    * @param inputModel
    * @param options
    */
-  async renderCompleteModel(model: ConstrainedMetaModel, inputModel: InputMetaModel, options: TypeScriptRenderCompleteModelOptions): Promise<RenderOutput> {
+  async renderCompleteModel(model: ConstrainedMetaModel, inputModel: InputMetaModel, {moduleSystem = 'ESM', exportType = 'default'}: TypeScriptRenderCompleteModelOptions): Promise<RenderOutput> {
+    // Shallow copy presets so that we can restore it once we are done
+    const originalPresets = [...(this.options.presets ? this.options.presets : [])];
+
+    // Add preset that adds the `export` keyword if it hasn't already been added
+    if (
+      moduleSystem === 'ESM' &&
+      exportType === 'named' &&
+      !hasPreset(originalPresets, TS_EXPORT_KEYWORD_PRESET)
+    ) {
+      this.options.presets = [TS_EXPORT_KEYWORD_PRESET, ...originalPresets];
+    }
+
     const outputModel = await this.render(model, inputModel);
     const modelDependencies = model.getNearestDependencies();
     //Create the correct dependency imports
-    const modelDependencyImports = modelDependencies.map((formattedDependencyModelName) => {
-      if (options.moduleSystem === 'CJS') {
-        return `const ${formattedDependencyModelName} = require('./${formattedDependencyModelName}');`;
-      }
-      return `import ${formattedDependencyModelName} from './${formattedDependencyModelName}';`;
+    const modelDependencyImports = modelDependencies.map(({name}) => {
+      const dependencyObject =
+        exportType === 'named' ? `{${name}}` : name;
+
+      return moduleSystem === 'CJS'
+        ? `const ${dependencyObject} = require('./${name}');`
+        : `import ${dependencyObject} from './${name}';`;
     });
 
-    //Ensure we expose the model correctly, based on the module system
-    let modelCode = `${outputModel.result}
-export default ${outputModel.renderedName};
-`;
-    if (options.moduleSystem === 'CJS') {
-      modelCode = `${outputModel.result}
-module.exports = ${outputModel.renderedName};`;
-    }
+    //Ensure we expose the model correctly, based on the module system and export type
+    const cjsExport =
+      exportType === 'default'
+        ? `module.exports = ${outputModel.renderedName};`
+        : `exports.${outputModel.renderedName} = ${outputModel.renderedName};`;
+    const esmExport =
+      exportType === 'default'
+        ? `export default ${outputModel.renderedName};\n`
+        : '';
+    const modelCode = `${outputModel.result}\n${moduleSystem === 'CJS' ? cjsExport : esmExport}`;
 
     const outputContent = `${[...modelDependencyImports, ...outputModel.dependencies].join('\n')}
-
 ${modelCode}`;
+
+    // Restore presets array from original copy
+    this.options.presets = originalPresets;
+
     return RenderOutput.toRenderOutput({ result: outputContent, renderedName: outputModel.renderedName, dependencies: outputModel.dependencies });
   }
 
diff --git a/src/generators/typescript/TypeScriptObjectRenderer.ts b/src/generators/typescript/TypeScriptObjectRenderer.ts
index 5a744e03..b1c99b9b 100644
--- a/src/generators/typescript/TypeScriptObjectRenderer.ts
+++ b/src/generators/typescript/TypeScriptObjectRenderer.ts
@@ -34,7 +34,7 @@ export abstract class TypeScriptObjectRenderer extends TypeScriptRenderer<Constr
   }
 
   renderProperty(property: ConstrainedObjectPropertyModel): string {
-    return `${property.propertyName}: ${property.property.type};`;
+    return `${property.propertyName}${property.required === false ? '?' : ''}: ${property.property.type};`;
   }
 
   runPropertyPreset(property: ConstrainedObjectPropertyModel): Promise<string> {
diff --git a/src/generators/typescript/TypeScriptPreset.ts b/src/generators/typescript/TypeScriptPreset.ts
index aaba0cd1..17504ad4 100644
--- a/src/generators/typescript/TypeScriptPreset.ts
+++ b/src/generators/typescript/TypeScriptPreset.ts
@@ -10,14 +10,14 @@ export type InterfacePresetType<O> = InterfacePreset<InterfaceRenderer, O>;
 export type EnumPresetType<O> = EnumPreset<EnumRenderer, O>;
 export type TypePresetType<O> = CommonPreset<TypeRenderer, O, ConstrainedMetaModel>
 
-export type TypeScriptPreset<O = TypeScriptOptions> = Preset<{
+export type TypeScriptPreset<O = any> = Preset<{
   class: ClassPresetType<O>;
   interface: InterfacePresetType<O>;
   enum: EnumPresetType<O>;
   type: TypePresetType<O>;
 }>;
 
-export const TS_DEFAULT_PRESET: TypeScriptPreset = {
+export const TS_DEFAULT_PRESET: TypeScriptPreset<TypeScriptOptions> = {
   class: TS_DEFAULT_CLASS_PRESET,
   interface: TS_DEFAULT_INTERFACE_PRESET,
   enum: TS_DEFAULT_ENUM_PRESET,
diff --git a/src/generators/typescript/constrainer/EnumConstrainer.ts b/src/generators/typescript/constrainer/EnumConstrainer.ts
index 3452d5b2..2b177396 100644
--- a/src/generators/typescript/constrainer/EnumConstrainer.ts
+++ b/src/generators/typescript/constrainer/EnumConstrainer.ts
@@ -35,8 +35,11 @@ export function defaultEnumKeyConstraints(customConstraints?: Partial<ModelEnumK
     constrainedEnumKey = constraints.NO_NUMBER_START_CHAR(constrainedEnumKey);
     constrainedEnumKey = constraints.NO_EMPTY_VALUE(constrainedEnumKey);
     constrainedEnumKey = constraints.NO_RESERVED_KEYWORDS(constrainedEnumKey);
+    //If the enum key has been manipulated, lets make sure it don't clash with existing keys
+    if (constrainedEnumKey !== enumKey) {
+      constrainedEnumKey = constraints.NO_DUPLICATE_KEYS(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER);
+    }
     constrainedEnumKey = constraints.NAMING_FORMATTER(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_DUPLICATE_KEYS(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER);
     return constrainedEnumKey;
   };
 }
diff --git a/src/generators/typescript/constrainer/PropertyKeyConstrainer.ts b/src/generators/typescript/constrainer/PropertyKeyConstrainer.ts
index 994a97f6..6fda3dff 100644
--- a/src/generators/typescript/constrainer/PropertyKeyConstrainer.ts
+++ b/src/generators/typescript/constrainer/PropertyKeyConstrainer.ts
@@ -21,7 +21,7 @@ export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
   NO_NUMBER_START_CHAR,
   NO_DUPLICATE_PROPERTIES,
   NO_EMPTY_VALUE,
-  NAMING_FORMATTER: FormatHelpers.toPascalCase,
+  NAMING_FORMATTER: FormatHelpers.toCamelCase,
   NO_RESERVED_KEYWORDS: (value: string) => {
     return NO_RESERVED_KEYWORDS(value, isReservedTypeScriptKeyword); 
   }
@@ -36,8 +36,11 @@ export function defaultPropertyKeyConstraints(customConstraints?: Partial<Proper
     constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
     constrainedPropertyKey = constraints.NO_EMPTY_VALUE(constrainedPropertyKey);
     constrainedPropertyKey = constraints.NO_RESERVED_KEYWORDS(constrainedPropertyKey);
+    //If the property name has been manipulated, lets make sure it don't clash with existing properties
+    if (constrainedPropertyKey !== objectPropertyModel.propertyName) {
+      constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER);
+    }
     constrainedPropertyKey = constraints.NAMING_FORMATTER(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER);
     return constrainedPropertyKey;
   };
 }
diff --git a/src/generators/typescript/presets/CommonPreset.ts b/src/generators/typescript/presets/CommonPreset.ts
index 792f1f6e..f3c69463 100644
--- a/src/generators/typescript/presets/CommonPreset.ts
+++ b/src/generators/typescript/presets/CommonPreset.ts
@@ -114,14 +114,16 @@ function renderUnmarshalProperties(model: ConstrainedObjectModel) {
     setDictionaryProperties.push(`if (instance.${prop} === undefined) {instance.${prop} = new Map();}`);
     unmarshalDictionaryProperties.push(`instance.${prop}.set(key, ${unmarshalCode});`);
   }
+  const corePropertyKeys = propertyNames.map((propertyKey) => `"${propertyKey}"`).join(',');
+  const unwrappedDictionaryCode = setDictionaryProperties.length > 0 ? `${setDictionaryProperties.join('\n')}
+  for (const [key, value] of Object.entries(obj).filter((([key,]) => {return ![${corePropertyKeys}].includes(key);}))) {
+    ${unmarshalDictionaryProperties.join('\n')}
+  }` : '';
 
   return `
 ${unmarshalNormalProperties.join('\n')}
 
-${setDictionaryProperties.join('\n')}
-for (const [key, value] of Object.entries(obj).filter((([key,]) => {return ![${propertyNames.join(',')}].includes(key);}))) {
-  ${unmarshalDictionaryProperties.join('\n')}
-}
+${unwrappedDictionaryCode}
 `;
 }
 
@@ -159,7 +161,7 @@ export const TS_COMMON_PRESET: TypeScriptPreset<TypeScriptCommonPresetOptions> =
       }
 
       if (options.example === true) {
-        blocks.push(renderExampleFunction({ renderer, model }));
+        blocks.push(renderExampleFunction({ model }));
       }
       
       return renderer.renderBlock([content, ...blocks], 2);
diff --git a/src/generators/typescript/presets/utils/ExampleFunction.ts b/src/generators/typescript/presets/utils/ExampleFunction.ts
index af6ba658..4dec0e6e 100644
--- a/src/generators/typescript/presets/utils/ExampleFunction.ts
+++ b/src/generators/typescript/presets/utils/ExampleFunction.ts
@@ -1,33 +1,33 @@
 import { ConstrainedArrayModel, ConstrainedBooleanModel, ConstrainedEnumModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedMetaModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedUnionModel } from '../../../../models';
-import { ClassRenderer } from '../../renderers/ClassRenderer';
 
 /**
  * Inferring first acceptable value from the model.
  * 
  * @param model 
- * @param renderer 
  */
-export function renderValueFromModel(model: ConstrainedMetaModel, renderer: ClassRenderer): string | undefined {
+export function renderValueFromModel(model: ConstrainedMetaModel): string | undefined {
   if (model instanceof ConstrainedEnumModel && model.values.length > 0) {
     //Greedy example
     return model.values[0].value;
   } else if (model instanceof ConstrainedReferenceModel) {
-    return `${model.type}.example()`;
+    return `${model.name}.example()`;
   } else if (model instanceof ConstrainedUnionModel && model.union.length > 0) {
     //Greedy example 
-    return renderValueFromModel(model.union[0], renderer);
+    return renderValueFromModel(model.union[0]);
   } else if (model instanceof ConstrainedArrayModel) {
-    const arrayType = renderValueFromModel(model.valueModel, renderer);
+    const arrayType = renderValueFromModel(model.valueModel);
     return `[${arrayType}]`;
   } else if (model instanceof ConstrainedTupleModel && model.tuple.length > 0) {
     const values = model.tuple.map((tupleModel) => {
-      return renderValueFromModel(tupleModel.value, renderer);
+      return renderValueFromModel(tupleModel.value);
     });
     return `[${values.join(',')}]`;
   } else if (model instanceof ConstrainedStringModel) {
     return '"string"';
-  } else if (model instanceof ConstrainedIntegerModel || model instanceof ConstrainedFloatModel) {
+  } else if (model instanceof ConstrainedIntegerModel) {
     return '0';
+  } else if (model instanceof ConstrainedFloatModel) {
+    return '0.0';
   } else if (model instanceof ConstrainedBooleanModel) {
     return 'true';
   } 
@@ -37,14 +37,13 @@ export function renderValueFromModel(model: ConstrainedMetaModel, renderer: Clas
 /**
  * Render `example` function based on model properties.
  */
-export default function renderExampleFunction({ renderer, model }: {
-  renderer: ClassRenderer,
+export default function renderExampleFunction({ model }: {
   model: ConstrainedObjectModel,
 }): string {
   const properties = model.properties || {};
   const setProperties = [];
   for (const [propertyName, property] of Object.entries(properties)) {
-    const potentialRenderedValue = renderValueFromModel(property.property, renderer);
+    const potentialRenderedValue = renderValueFromModel(property.property);
     if (potentialRenderedValue === undefined) {
       //Unable to determine example value, skip property.
       continue;
diff --git a/src/generators/typescript/renderers/ClassRenderer.ts b/src/generators/typescript/renderers/ClassRenderer.ts
index b6f5ebcc..2d2c03b2 100644
--- a/src/generators/typescript/renderers/ClassRenderer.ts
+++ b/src/generators/typescript/renderers/ClassRenderer.ts
@@ -71,9 +71,9 @@ ${renderer.indent(renderer.renderBlock(assignments))}
     return `private _${renderer.renderProperty(property)}`;
   },
   getter({ property }): string {
-    return `get ${property.propertyName}()${property.property.type} { return this._${property.propertyName}; }`;
+    return `get ${property.propertyName}(): ${property.property.type}${property.required === false ? ' | undefined' : ''} { return this._${property.propertyName}; }`;
   },
   setter({ property }): string {
-    return `set ${property.propertyName}(${property.propertyName}${property.property.type}) { this._${property.propertyName} = ${property.propertyName}; }`;
+    return `set ${property.propertyName}(${property.propertyName}: ${property.property.type}${property.required === false ? ' | undefined' : ''}) { this._${property.propertyName} = ${property.propertyName}; }`;
   },
 };
diff --git a/src/helpers/CommonModelToMetaModel.ts b/src/helpers/CommonModelToMetaModel.ts
index f7ddf81c..772af134 100644
--- a/src/helpers/CommonModelToMetaModel.ts
+++ b/src/helpers/CommonModelToMetaModel.ts
@@ -8,10 +8,6 @@ export function convertToMetaModel(jsonSchemaModel: CommonModel): MetaModel {
   if (anyModel !== undefined) {
     return anyModel;
   }
-  const unionModel = convertToUnionModel(jsonSchemaModel, modelName);
-  if (unionModel !== undefined) {
-    return unionModel;
-  }
   const enumModel = convertToEnumModel(jsonSchemaModel, modelName);
   if (enumModel !== undefined) {
     return enumModel;
@@ -28,6 +24,10 @@ export function convertToMetaModel(jsonSchemaModel: CommonModel): MetaModel {
   if (arrayModel !== undefined) {
     return arrayModel;
   }
+  const unionModel = convertToUnionModel(jsonSchemaModel, modelName);
+  if (unionModel !== undefined) {
+    return unionModel;
+  }
   const stringModel = convertToStringModel(jsonSchemaModel, modelName);
   if (stringModel !== undefined) {
     return stringModel;
@@ -116,7 +116,11 @@ export function convertToEnumModel(jsonSchemaModel: CommonModel, name: string):
   }
   const metaModel = new EnumModel(name, jsonSchemaModel.originalInput, []);
   for (const enumValue of jsonSchemaModel.enum) {
-    const enumValueModel = new EnumValueModel(JSON.stringify(enumValue), enumValue);
+    let enumKey = enumValue;
+    if (typeof enumValue !== 'string') {
+      enumKey = JSON.stringify(enumValue);
+    }
+    const enumValueModel = new EnumValueModel(enumKey, enumValue);
     metaModel.values.push(enumValueModel);
   }
   return metaModel;
diff --git a/src/helpers/ConstrainHelpers.ts b/src/helpers/ConstrainHelpers.ts
index 97656642..2c312ed9 100644
--- a/src/helpers/ConstrainHelpers.ts
+++ b/src/helpers/ConstrainHelpers.ts
@@ -169,7 +169,7 @@ function ConstrainEnumModel<Options>(typeMapping: TypeMapping<Options>, constrai
 
   for (const enumValue of context.metaModel.values) {
     const constrainedEnumKey = constrainRules.enumKey({enumKey: String(enumValue.key), enumModel: context.metaModel, constrainedEnumModel: constrainedModel});
-    const constrainedEnumValue = constrainRules.enumValue({enumValue: String(enumValue.value), enumModel: context.metaModel, constrainedEnumModel: constrainedModel});
+    const constrainedEnumValue = constrainRules.enumValue({enumValue: enumValue.value, enumModel: context.metaModel, constrainedEnumModel: constrainedModel});
 
     const constrainedEnumValueModel = new ConstrainedEnumValueModel(constrainedEnumKey, constrainedEnumValue);
     constrainedModel.values.push(constrainedEnumValueModel);
diff --git a/src/helpers/Constraints.ts b/src/helpers/Constraints.ts
index 8f8861ff..a9108688 100644
--- a/src/helpers/Constraints.ts
+++ b/src/helpers/Constraints.ts
@@ -43,25 +43,38 @@ export function NO_DUPLICATE_PROPERTIES(constrainedObjectModel: ConstrainedObjec
  * 
  * @param constrainedEnumModel the current constrained enum model, which contains already existing constrained enum keys
  * @param enumModel the raw enum model which is non-constrained to the output language.
- * @param enumKey one of the enum keys in enumModel which might have been manipulated
- * @param namingFormatter the name formatter which are used to format the enum key
- * @returns 
+ * @param enumKey one of the enum keys in enumModel which might have been manipulated.
+ * @param namingFormatter the name formatter which are used to format the enum key.
+ * @param enumKeyToCheck the enum key to use for checking if it already exist, defaults to enumKey.
+ * @param onNameChange callback to change the name of the enum key that needs to be returned.
+ * @param onNameChangeToCheck callback to change the enum key which is being checked as part of the existing models.
+ * @returns {string} the potential new enum key that does not clash with existing enum keys.
  */
-export function NO_DUPLICATE_ENUM_KEYS(constrainedEnumModel: ConstrainedEnumModel, enumModel: EnumModel, enumKey: string, namingFormatter: (value: string) => string): string {
-  const formattedEnumKey = namingFormatter(enumKey);
+export function NO_DUPLICATE_ENUM_KEYS(
+  constrainedEnumModel: ConstrainedEnumModel, 
+  enumModel: EnumModel, 
+  enumKey: string,
+  namingFormatter: (value: string) => string,
+  enumKeyToCheck: string = enumKey,
+  onNameChange: (currentEnumKey: string) => string = (currentEnumKey) => {
+    return `reserved_${currentEnumKey}`;
+  },
+  onNameChangeToCheck: (currentEnumKey: string) => string = onNameChange): string {
+  const formattedEnumKey = namingFormatter(enumKeyToCheck);
   let newEnumKey = enumKey;
 
   const alreadyPartOfMetaModel = enumModel.values
     .map((model) => model.key)
-    .filter((key) => enumKey !== key)
+    .filter((key) => enumKeyToCheck !== key)
     .includes(formattedEnumKey);
   const alreadyPartOfConstrainedModel = constrainedEnumModel.values
     .map((model) => model.key)
     .includes(formattedEnumKey);
   
   if (alreadyPartOfMetaModel || alreadyPartOfConstrainedModel) {
-    newEnumKey = `reserved_${enumKey}`;
-    newEnumKey = NO_DUPLICATE_ENUM_KEYS(constrainedEnumModel, enumModel, newEnumKey, namingFormatter);
+    newEnumKey = onNameChange(newEnumKey);
+    enumKeyToCheck = onNameChangeToCheck(enumKeyToCheck);
+    newEnumKey = NO_DUPLICATE_ENUM_KEYS(constrainedEnumModel, enumModel, newEnumKey, namingFormatter, enumKeyToCheck, onNameChange, onNameChangeToCheck);
   }
   return newEnumKey;
 }
diff --git a/src/helpers/index.ts b/src/helpers/index.ts
index c3ae019f..15915d92 100644
--- a/src/helpers/index.ts
+++ b/src/helpers/index.ts
@@ -5,3 +5,4 @@ export * from './CommonModelToMetaModel';
 export * from './Splitter';
 export * from './Constraints';
 export * from './ConstrainHelpers';
+export * from './PresetHelpers';


Test patch:
diff --git a/test/generators/go/Constants.spec.ts b/test/generators/go/Constants.spec.ts
new file mode 100644
index 00000000..03bfb69b
--- /dev/null
+++ b/test/generators/go/Constants.spec.ts
@@ -0,0 +1,35 @@
+import { isReservedGoKeyword } from '../../../src/generators/go/Constants';
+
+describe('Constants', () => {
+  it('should return true if the word is a reserved keyword', () => {
+    expect(isReservedGoKeyword('break')).toBe(true);
+    expect(isReservedGoKeyword('case')).toBe(true);
+    expect(isReservedGoKeyword('chan')).toBe(true);
+    expect(isReservedGoKeyword('const')).toBe(true);
+    expect(isReservedGoKeyword('continue')).toBe(true);
+    expect(isReservedGoKeyword('default')).toBe(true);
+    expect(isReservedGoKeyword('defer')).toBe(true);
+    expect(isReservedGoKeyword('else')).toBe(true);
+    expect(isReservedGoKeyword('fallthrough')).toBe(true);
+    expect(isReservedGoKeyword('for')).toBe(true);
+    expect(isReservedGoKeyword('func')).toBe(true);
+    expect(isReservedGoKeyword('go')).toBe(true);
+    expect(isReservedGoKeyword('goto')).toBe(true);
+    expect(isReservedGoKeyword('if')).toBe(true);
+    expect(isReservedGoKeyword('import')).toBe(true);
+    expect(isReservedGoKeyword('interface')).toBe(true);
+    expect(isReservedGoKeyword('map')).toBe(true);
+    expect(isReservedGoKeyword('package')).toBe(true);
+    expect(isReservedGoKeyword('range')).toBe(true);
+    expect(isReservedGoKeyword('return')).toBe(true);
+    expect(isReservedGoKeyword('select')).toBe(true);
+    expect(isReservedGoKeyword('struct')).toBe(true);
+    expect(isReservedGoKeyword('switch')).toBe(true);
+    expect(isReservedGoKeyword('type')).toBe(true);
+    expect(isReservedGoKeyword('var')).toBe(true);
+  });
+
+  it('should return false if the word is not a reserved keyword', () => {
+    expect(isReservedGoKeyword('enum')).toBe(false);
+  });
+});
diff --git a/test/generators/go/GoConstrainer.spec.ts b/test/generators/go/GoConstrainer.spec.ts
index 58a281b6..071ec1d6 100644
--- a/test/generators/go/GoConstrainer.spec.ts
+++ b/test/generators/go/GoConstrainer.spec.ts
@@ -1,16 +1,10 @@
 import {GoDefaultTypeMapping } from '../../../src/generators/go/GoConstrainer';
-import {MockGoRenderer} from '../../TestUtils/TestRenderers';
-import { GoRenderer } from '../../../src/generators/go/GoRenderer';
-import { CommonInputModel, CommonModel, ConstrainedAnyModel, ConstrainedArrayModel, ConstrainedBooleanModel, ConstrainedDictionaryModel, ConstrainedEnumModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedUnionModel, GoGenerator } from '../../../src';
+import { ConstrainedAnyModel, ConstrainedArrayModel, ConstrainedBooleanModel, ConstrainedDictionaryModel, ConstrainedEnumModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedUnionModel, GoGenerator } from '../../../src';
 describe('GoConstrainer', () => {
-  let renderer: GoRenderer;
-  beforeEach(() => {
-    renderer = new MockGoRenderer(GoGenerator.defaultOptions, new GoGenerator(), [], new CommonModel(), new CommonInputModel());
-  });
   describe('ObjectModel', () => { 
     test('should render the constrained name as type', () => {
       const model = new ConstrainedObjectModel('test', undefined, '', {});
-      const type = GoDefaultTypeMapping.Object({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Object({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual(model.name);
     });
   });
@@ -18,42 +12,42 @@ describe('GoConstrainer', () => {
     test('should render the constrained name as type', () => {
       const refModel = new ConstrainedAnyModel('test', undefined, '');
       const model = new ConstrainedReferenceModel('test', undefined, '', refModel);
-      const type = GoDefaultTypeMapping.Reference({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Reference({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual(model.name);
     });
   });
   describe('Any', () => { 
     test('should render type', () => {
       const model = new ConstrainedAnyModel('test', undefined, '');
-      const type = GoDefaultTypeMapping.Any({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Any({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual('interface{}');
     });
   });
   describe('Float', () => { 
     test('should render type', () => {
       const model = new ConstrainedFloatModel('test', undefined, '');
-      const type = GoDefaultTypeMapping.Float({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Float({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual('float64');
     });
   });
   describe('Integer', () => { 
     test('should render type', () => {
       const model = new ConstrainedIntegerModel('test', undefined, '');
-      const type = GoDefaultTypeMapping.Integer({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Integer({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual('int');
     });
   });
   describe('String', () => { 
     test('should render type', () => {
       const model = new ConstrainedStringModel('test', undefined, '');
-      const type = GoDefaultTypeMapping.String({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.String({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual('string');
     });
   });
   describe('Boolean', () => { 
     test('should render type', () => {
       const model = new ConstrainedBooleanModel('test', undefined, '');
-      const type = GoDefaultTypeMapping.Boolean({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Boolean({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual('bool');
     });
   });
@@ -61,7 +55,7 @@ describe('GoConstrainer', () => {
   describe('Tuple', () => { 
     test('should render type', () => {
       const model = new ConstrainedTupleModel('test', undefined, '', []);
-      const type = GoDefaultTypeMapping.Tuple({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Tuple({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual('[]interface{}');
     });
   });
@@ -70,7 +64,7 @@ describe('GoConstrainer', () => {
     test('should render type', () => {
       const arrayModel = new ConstrainedStringModel('test', undefined, 'string');
       const model = new ConstrainedArrayModel('test', undefined, '', arrayModel);
-      const type = GoDefaultTypeMapping.Array({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Array({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual('[]string');
     });
   });
@@ -78,7 +72,7 @@ describe('GoConstrainer', () => {
   describe('Enum', () => { 
     test('should render the constrained name as type', () => {
       const model = new ConstrainedEnumModel('test', undefined, '', []);
-      const type = GoDefaultTypeMapping.Enum({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Enum({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual(model.name);
     });
   });
@@ -86,7 +80,7 @@ describe('GoConstrainer', () => {
   describe('Union', () => { 
     test('should render type', () => {
       const model = new ConstrainedUnionModel('test', undefined, '', []);
-      const type = GoDefaultTypeMapping.Union({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Union({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual('interface{}');
     });
   });
@@ -96,7 +90,7 @@ describe('GoConstrainer', () => {
       const keyModel = new ConstrainedStringModel('test', undefined, 'string');
       const valueModel = new ConstrainedStringModel('test', undefined, 'string');
       const model = new ConstrainedDictionaryModel('test', undefined, '', keyModel, valueModel);
-      const type = GoDefaultTypeMapping.Dictionary({constrainedModel: model, renderer});
+      const type = GoDefaultTypeMapping.Dictionary({constrainedModel: model, options: GoGenerator.defaultOptions});
       expect(type).toEqual('map[string]string');
     });
   });
diff --git a/test/generators/go/GoGenerator.spec.ts b/test/generators/go/GoGenerator.spec.ts
index 59791671..df6a56b8 100644
--- a/test/generators/go/GoGenerator.spec.ts
+++ b/test/generators/go/GoGenerator.spec.ts
@@ -5,39 +5,6 @@ describe('GoGenerator', () => {
   beforeEach(() => {
     generator = new GoGenerator();
   });
-
-  it('should return true if the word is a reserved keyword', () => {
-    expect(generator.reservedGoKeyword('break')).toBe(true);
-    expect(generator.reservedGoKeyword('case')).toBe(true);
-    expect(generator.reservedGoKeyword('chan')).toBe(true);
-    expect(generator.reservedGoKeyword('const')).toBe(true);
-    expect(generator.reservedGoKeyword('continue')).toBe(true);
-    expect(generator.reservedGoKeyword('default')).toBe(true);
-    expect(generator.reservedGoKeyword('defer')).toBe(true);
-    expect(generator.reservedGoKeyword('else')).toBe(true);
-    expect(generator.reservedGoKeyword('fallthrough')).toBe(true);
-    expect(generator.reservedGoKeyword('for')).toBe(true);
-    expect(generator.reservedGoKeyword('func')).toBe(true);
-    expect(generator.reservedGoKeyword('go')).toBe(true);
-    expect(generator.reservedGoKeyword('goto')).toBe(true);
-    expect(generator.reservedGoKeyword('if')).toBe(true);
-    expect(generator.reservedGoKeyword('import')).toBe(true);
-    expect(generator.reservedGoKeyword('interface')).toBe(true);
-    expect(generator.reservedGoKeyword('map')).toBe(true);
-    expect(generator.reservedGoKeyword('package')).toBe(true);
-    expect(generator.reservedGoKeyword('range')).toBe(true);
-    expect(generator.reservedGoKeyword('return')).toBe(true);
-    expect(generator.reservedGoKeyword('select')).toBe(true);
-    expect(generator.reservedGoKeyword('struct')).toBe(true);
-    expect(generator.reservedGoKeyword('switch')).toBe(true);
-    expect(generator.reservedGoKeyword('type')).toBe(true);
-    expect(generator.reservedGoKeyword('var')).toBe(true);
-  });
-
-  it('should return false if the word is not a reserved keyword', () => {
-    expect(generator.reservedGoKeyword('enum')).toBe(false);
-  });
-
   test('should render `struct` type', async () => {
     const doc = {
       $id: '_address',
@@ -62,30 +29,10 @@ describe('GoGenerator', () => {
         }
       },
     };
-    const expected = `// Address represents a Address model.
-type Address struct {
-  StreetName string
-  City string
-  State string
-  HouseNumber float64
-  Marriage bool
-  Members []interface{}
-  TupleType []interface{}
-  ArrayType []string
-  AdditionalProperties map[string]string
-  STestPatternProperties map[string]string
-}`;
 
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['_address'];
-
-    let structModel = await generator.renderStruct(model, inputModel);
-    expect(structModel.result).toEqual(expected);
-    expect(structModel.dependencies).toEqual([]);
-
-    structModel = await generator.render(model, inputModel);
-    expect(structModel.result).toEqual(expected);
-    expect(structModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
   });
 
   test('should work custom preset for `struct` type', async () => {
@@ -99,71 +46,31 @@ type Address struct {
         type: 'string'
       }
     };
-    const expected = `// CustomStruct represents a CustomStruct model.
-type CustomStruct struct {
-  property string
-  additionalProperties string
-}`;
-
     generator = new GoGenerator({
       presets: [
         {
           struct: {
-            field({ fieldName, field, renderer }) {
-              return `${fieldName} ${renderer.renderType(field)}`; // private fields
+            field({ field }) {
+              return `${field.propertyName} ${field.property.type}`; // private fields
             },
           }
         }
       ]
     });
 
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['CustomStruct'];
-
-    const structModel = await generator.render(model, inputModel);
-    expect(structModel.result).toEqual(expected);
-    expect(structModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
   });
 
-  describe.each([
-    {
-      name: 'with enums sharing same type',
-      doc: {
-        $id: 'States',
-        type: 'string',
-        enum: ['Texas', 'Alabama', 'California'],
-      },
-      expected: `// States represents an enum of string.
-type States string
-
-const (
-  StatesTexas States = "Texas"
-  StatesAlabama = "Alabama"
-  StatesCalifornia = "California"
-)`,
-    },
-    {
-      name: 'with enums of mixed types',
-      doc: {
-        $id: 'Things',
-        enum: ['Texas', 1, '1', false, { test: 'test' }],
-      },
-      expected: `// Things represents an enum of mixed types.
-type Things interface{}`,
-    },
-  ])('should render `enum` type $name', ({ doc, expected }) => {
-    test('should not be empty', async () => {
-      const inputModel = await generator.process(doc);
-      const model = inputModel.models[doc.$id];
-
-      let enumModel = await generator.render(model, inputModel);
-      expect(enumModel.result).toEqual(expected);
-      expect(enumModel.dependencies).toEqual([]);
-
-      enumModel = await generator.renderEnum(model, inputModel);
-      expect(enumModel.result).toEqual(expected);
-      expect(enumModel.dependencies).toEqual([]);
-    });
+  test('should render `enum` with mixed types', async () => {
+    const doc = {
+      $id: 'Things',
+      enum: ['Texas', 1, '1', false, { test: 'test' }],
+    };
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
   });
 
   test('should work custom preset for `enum` type', async () => {
@@ -172,14 +79,6 @@ type Things interface{}`,
       type: 'string',
       enum: ['Texas', 'Alabama', 'California'],
     };
-    const expected = `// CustomEnum represents an enum of string.
-type CustomEnum string
-
-const (
-  CustomEnumTexas CustomEnum = "Texas"
-  CustomEnumAlabama = "Alabama"
-  CustomEnumCalifornia = "California"
-)`;
 
     generator = new GoGenerator({
       presets: [
@@ -193,16 +92,9 @@ const (
       ]
     });
 
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['CustomEnum'];
-
-    let enumModel = await generator.render(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
-
-    enumModel = await generator.renderEnum(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
   });
   describe('generateCompleteModels()', () => {
     test('should render models', async () => {
@@ -271,6 +163,8 @@ const (
       expect(models).toHaveLength(2);
       expect(models[0].result).toMatchSnapshot();
       expect(models[1].result).toMatchSnapshot();
+      expect(models[0].dependencies).toEqual(['time']);
+      expect(models[1].dependencies).toEqual(['time']);
     });
   });
 });
diff --git a/test/generators/go/GoRenderer.spec.ts b/test/generators/go/GoRenderer.spec.ts
index 933a79ea..8ecd475a 100644
--- a/test/generators/go/GoRenderer.spec.ts
+++ b/test/generators/go/GoRenderer.spec.ts
@@ -1,72 +1,28 @@
 import { GoGenerator } from '../../../src/generators/go/GoGenerator';
 import { GoRenderer } from '../../../src/generators/go/GoRenderer';
-import { CommonInputModel, CommonModel } from '../../../src/models';
-class MockGoRenderer extends GoRenderer {
+import { ConstrainedObjectModel, InputMetaModel } from '../../../src/models';
+import { MockGoRenderer } from '../../TestUtils/TestRenderers';
 
-}
 describe('GoRenderer', () => {
-  let renderer: MockGoRenderer;
+  let renderer: GoRenderer<any>;
   beforeEach(() => {
-    renderer = new MockGoRenderer(GoGenerator.defaultOptions, new GoGenerator(), [], new CommonModel(), new CommonInputModel());
+    renderer = new MockGoRenderer(GoGenerator.defaultOptions, new GoGenerator(), [], new ConstrainedObjectModel('', undefined, '', {}), new InputMetaModel());
   });
-
-  describe('toGoType()', () => {
-    test('Should render undefined as interface type', () => {
-      expect(renderer.toGoType(undefined, new CommonModel())).toEqual('interface{}');
-    });
-    test('Should render integer as int type', () => {
-      expect(renderer.toGoType('integer', new CommonModel())).toEqual('int');
-    });
-    test('Should render number as float64 type', () => {
-      expect(renderer.toGoType('number', new CommonModel())).toEqual('float64');
-    });
-    test('Should render array as slice of the type', () => {
-      const model = new CommonModel();
-      model.items = CommonModel.toCommonModel({ type: 'number' });
-      expect(renderer.toGoType('array', model)).toEqual('[]float64');
-    });
-    test('Should render tuple with one type as slice of that type', () => {
-      const model = new CommonModel();
-      model.items = [CommonModel.toCommonModel({ type: 'number' })];
-      expect(renderer.toGoType('array', model)).toEqual('[]float64');
-    });
-    test('Should render tuple with multiple types as slice of interface{}', () => {
-      const model = new CommonModel();
-      model.items = [CommonModel.toCommonModel({ type: 'number' }), CommonModel.toCommonModel({ type: 'string' })];
-      expect(renderer.toGoType('array', model)).toEqual('[]interface{}');
-    });
-    test('Should render object as interface type', () => {
-      expect(renderer.toGoType('object', new CommonModel())).toEqual('interface{}');
-    });
-  });
-  describe('nameType()', () => {
-    test('Should call naming convention', () => {
-      const name = renderer.nameType('type__someType');
-      expect(name).toEqual('TypeSomeType');
-    });
-  });
-  describe('nameField()', () => {
-    test('Should call naming convention', () => {
-      const name = renderer.nameField('field__someField');
-      expect(name).toEqual('FieldSomeField');
-    });
-  });
-  describe('renderType()', () => {
-    test('Should render refs using type naming convention', () => {
-      const model = new CommonModel();
-      model.$ref = '<anonymous-schema-1>';
-      const renderedType = renderer.renderType(model);
-      expect(renderedType).toEqual('*AnonymousSchema1');
-    });
-    test('Should render union types with one type as slice of that type', () => {
-      const model = CommonModel.toCommonModel({ type: ['number'] });
-      const renderedType = renderer.renderType(model);
-      expect(renderedType).toEqual('[]float64');
-    });
-    test('Should render union types with multiple types as slice of interface', () => {
-      const model = CommonModel.toCommonModel({ type: ['number', 'string'] });
-      const renderedType = renderer.renderType(model);
-      expect(renderedType).toEqual('[]interface{}');
+  describe('renderComments()', () => {
+    test('should render single lines correctly', () => {
+      const lines = 'test';
+      const renderedLines = renderer.renderComments(lines);
+      expect(renderedLines).toMatchSnapshot();
+    });
+    test('should render multiple lines correctly', () => {
+      const lines = ['test', 'test2'];
+      const renderedLines = renderer.renderComments(lines);
+      expect(renderedLines).toMatchSnapshot();
+    });
+    test('should render no lines', () => {
+      const lines: string[] = [];
+      const renderedLines = renderer.renderComments(lines);
+      expect(renderedLines).toMatchSnapshot();
     });
   });
 });
diff --git a/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap b/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap
index 4a89f5ac..33094e82 100644
--- a/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap
+++ b/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap
@@ -13,11 +13,10 @@ type Address struct {
   State string
   HouseNumber float64
   Marriage bool
-  Members []interface{}
+  Members interface{}
   ArrayType []interface{}
   OtherModel *OtherModel
-  AdditionalProperties map[string][]interface{}
-  STestPatternProperties map[string]string
+  AdditionalProperties map[string]interface{}
 }"
 `;
 
@@ -30,7 +29,7 @@ import (
 // OtherModel represents a OtherModel model.
 type OtherModel struct {
   StreetName string
-  AdditionalProperties map[string][]interface{}
+  AdditionalProperties map[string]interface{}
 }"
 `;
 
@@ -45,11 +44,10 @@ type Address struct {
   State string
   HouseNumber float64
   Marriage bool
-  Members []interface{}
+  Members interface{}
   ArrayType []interface{}
   OtherModel *OtherModel
-  AdditionalProperties map[string][]interface{}
-  STestPatternProperties map[string]string
+  AdditionalProperties map[string]interface{}
 }"
 `;
 
@@ -60,6 +58,87 @@ package some_package
 // OtherModel represents a OtherModel model.
 type OtherModel struct {
   StreetName string
-  AdditionalProperties map[string][]interface{}
+  AdditionalProperties map[string]interface{}
+}"
+`;
+
+exports[`GoGenerator should render \`enum\` with mixed types 1`] = `
+"// Things represents an enum of Things.
+type Things uint
+
+const (
+  ThingsTexas Things = iota
+  ThingsNumber_1
+  ThingsReservedNumber_1
+  ThingsFalse
+  ThingsCurlyleftQuotationTestQuotationColonQuotationTestQuotationCurlyright
+)
+
+// Value returns the value of the enum.
+func (op Things) Value() any {
+	if op >= Things(len(ThingsValues)) {
+		return nil
+	}
+	return ThingsValues[op]
+}
+
+var ThingsValues = []any{\\"Texas\\",1,\\"1\\",false,{\\"test\\":\\"test\\"}}
+var ValuesToThings = map[any]Things{
+  ThingsValues[ThingsTexas]: ThingsTexas,
+  ThingsValues[ThingsNumber_1]: ThingsNumber_1,
+  ThingsValues[ThingsReservedNumber_1]: ThingsReservedNumber_1,
+  ThingsValues[ThingsFalse]: ThingsFalse,
+  ThingsValues[ThingsCurlyleftQuotationTestQuotationColonQuotationTestQuotationCurlyright]: ThingsCurlyleftQuotationTestQuotationColonQuotationTestQuotationCurlyright,
+}
+"
+`;
+
+exports[`GoGenerator should render \`struct\` type 1`] = `
+"// Address represents a Address model.
+type Address struct {
+  StreetName string
+  City string
+  State string
+  HouseNumber float64
+  Marriage bool
+  Members interface{}
+  TupleType []interface{}
+  ArrayType []interface{}
+  AdditionalProperties map[string]string
+}"
+`;
+
+exports[`GoGenerator should work custom preset for \`enum\` type 1`] = `
+"// CustomEnum represents an enum of CustomEnum.
+type CustomEnum uint
+
+const (
+  CustomEnumTexas CustomEnum = iota
+  CustomEnumAlabama
+  CustomEnumCalifornia
+)
+
+// Value returns the value of the enum.
+func (op CustomEnum) Value() any {
+	if op >= CustomEnum(len(CustomEnumValues)) {
+		return nil
+	}
+	return CustomEnumValues[op]
+}
+
+var CustomEnumValues = []any{\\"Texas\\",\\"Alabama\\",\\"California\\"}
+var ValuesToCustomEnum = map[any]CustomEnum{
+  CustomEnumValues[CustomEnumTexas]: CustomEnumTexas,
+  CustomEnumValues[CustomEnumAlabama]: CustomEnumAlabama,
+  CustomEnumValues[CustomEnumCalifornia]: CustomEnumCalifornia,
+}
+"
+`;
+
+exports[`GoGenerator should work custom preset for \`struct\` type 1`] = `
+"// CustomStruct represents a CustomStruct model.
+type CustomStruct struct {
+  Property string
+  AdditionalProperties map[string]string
 }"
 `;
diff --git a/test/generators/go/__snapshots__/GoRenderer.spec.ts.snap b/test/generators/go/__snapshots__/GoRenderer.spec.ts.snap
new file mode 100644
index 00000000..7f81781e
--- /dev/null
+++ b/test/generators/go/__snapshots__/GoRenderer.spec.ts.snap
@@ -0,0 +1,10 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`GoRenderer renderComments() should render multiple lines correctly 1`] = `
+"// test
+// test2"
+`;
+
+exports[`GoRenderer renderComments() should render no lines 1`] = `""`;
+
+exports[`GoRenderer renderComments() should render single lines correctly 1`] = `"// test"`;
diff --git a/test/generators/go/constrainer/EnumConstrainer.spec.ts b/test/generators/go/constrainer/EnumConstrainer.spec.ts
index 7d87c73e..2175a35e 100644
--- a/test/generators/go/constrainer/EnumConstrainer.spec.ts
+++ b/test/generators/go/constrainer/EnumConstrainer.spec.ts
@@ -1,5 +1,5 @@
 import { GoDefaultConstraints } from '../../../../src/generators/go/GoConstrainer';
-import {EnumModel} from '../../../../src/models/MetaModel';
+import { EnumModel } from '../../../../src/models/MetaModel';
 import { ConstrainedEnumModel, ConstrainedEnumValueModel } from '../../../../src';
 import { defaultEnumKeyConstraints, ModelEnumKeyConstraints, DefaultEnumKeyConstraints } from '../../../../src/generators/go/constrainer/EnumConstrainer';
 describe('EnumConstrainer', () => {
@@ -9,29 +9,29 @@ describe('EnumConstrainer', () => {
   describe('enum keys', () => {
     test('should never render special chars', () => {
       const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: '%'});
-      expect(constrainedKey).toEqual('PERCENT');
+      expect(constrainedKey).toEqual('TestPercent');
     });
     test('should not render number as start char', () => {
       const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: '1'});
-      expect(constrainedKey).toEqual('NUMBER_1');
+      expect(constrainedKey).toEqual('TestNumber_1');
     });
     test('should not contain duplicate keys', () => {
-      const existingConstrainedEnumValueModel = new ConstrainedEnumValueModel('TEST', 'test');
+      const existingConstrainedEnumValueModel = new ConstrainedEnumValueModel('TestEmpty', 'TestEmpty');
       const constrainedEnumModel = new ConstrainedEnumModel('test', undefined, '', [existingConstrainedEnumValueModel]);
-      const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'TEST'});
-      expect(constrainedKey).toEqual('RESERVED_TEST');
+      const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: ''});
+      expect(constrainedKey).toEqual('TestReservedEmpty');
     });
     test('should never contain empty keys', () => {
       const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: ''});
-      expect(constrainedKey).toEqual('EMPTY');
+      expect(constrainedKey).toEqual('TestEmpty');
     });
     test('should use constant naming format', () => {
       const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'some weird_value!"#2'});
-      expect(constrainedKey).toEqual('SOME_SPACE_WEIRD_VALUE_EXCLAMATION_QUOTATION_HASH_2');
+      expect(constrainedKey).toEqual('TestSomeSpaceWeirdValueExclamationQuotationHash_2');
     });
     test('should never render reserved keywords', () => {
       const constrainedKey = GoDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'return'});
-      expect(constrainedKey).toEqual('RESERVED_RETURN');
+      expect(constrainedKey).toEqual('TestReservedReturn');
     });
   });
   describe('enum values', () => {
@@ -41,33 +41,32 @@ describe('EnumConstrainer', () => {
     });
     test('should render boolean values', () => {
       const constrainedValue = GoDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: true});
-      expect(constrainedValue).toEqual('"true"');
+      expect(constrainedValue).toEqual('true');
     });
-    test.skip('should render numbers', () => {
+    test('should render numbers', () => {
       const constrainedValue = GoDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: 123});
       expect(constrainedValue).toEqual(123);
     });
-    test.skip('should render object', () => {
+    test('should render object', () => {
       const constrainedValue = GoDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: {test: 'test'}});
-      expect(constrainedValue).toEqual('"{\\"test\\":\\"test\\"}"');
+      expect(constrainedValue).toEqual('{"test":"test"}');
     });
     test('should render unknown value', () => {
       const constrainedValue = GoDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: undefined});
-      expect(constrainedValue).toEqual('"undefined"');
+      expect(constrainedValue).toEqual(undefined);
     });
   });
   describe('custom constraints', () => {
     test('should be able to handle undefined', () => {
       const constrainFunction = defaultEnumKeyConstraints(undefined);
       const value = constrainFunction({enumModel, constrainedEnumModel, enumKey: 'TEST'});
-      expect(value).toEqual('TEST');
+      expect(value).toEqual('TestTest');
     });
     test('should be able to overwrite all hooks for enum key', () => {
-      const mockedConstraintCallbacks: ModelEnumKeyConstraints = {
+      const mockedConstraintCallbacks: Partial<ModelEnumKeyConstraints> = {
         NAMING_FORMATTER: jest.fn().mockReturnValue(''),
         NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
         NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
-        NO_DUPLICATE_KEYS: jest.fn().mockReturnValue(''),
         NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
         NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue('')
       };
diff --git a/test/generators/go/constrainer/PropertyKeyConstrainer.spec.ts b/test/generators/go/constrainer/PropertyKeyConstrainer.spec.ts
index 561720b8..3d95fbfa 100644
--- a/test/generators/go/constrainer/PropertyKeyConstrainer.spec.ts
+++ b/test/generators/go/constrainer/PropertyKeyConstrainer.spec.ts
@@ -7,7 +7,7 @@ describe('PropertyKeyConstrainer', () => {
 
   const constrainPropertyName = (propertyName: string) => {
     const objectPropertyModel = new ObjectPropertyModel(propertyName, false, objectModel);
-    const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', objectPropertyModel.required, constrainedObjectModel);
+    const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', '', objectPropertyModel.required, constrainedObjectModel);
     return GoDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel });
   };
 
@@ -30,11 +30,14 @@ describe('PropertyKeyConstrainer', () => {
   test('should not contain duplicate properties', () => {
     const objectModel = new ObjectModel('test', undefined, {});
     const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {});
-    const objectPropertyModel = new ObjectPropertyModel('SomeProperty', false, objectModel);
-    const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('SomeProperty', objectPropertyModel.required, constrainedObjectModel);
-    constrainedObjectModel.properties['SomeProperty'] = constrainedObjectPropertyModel;
-    const constrainedKey = GoDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel});
-    expect(constrainedKey).toEqual('ReservedSomeProperty');
+    const objectPropertyModel = new ObjectPropertyModel('ReservedReturn', false, objectModel);
+    const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('ReservedReturn', '', objectPropertyModel.required, constrainedObjectModel);
+    const objectPropertyModel2 = new ObjectPropertyModel('return', false, objectModel);
+    const constrainedObjectPropertyModel2 = new ConstrainedObjectPropertyModel('return', '', objectPropertyModel.required, constrainedObjectModel);
+    constrainedObjectModel.properties['ReservedReturn'] = constrainedObjectPropertyModel;
+    constrainedObjectModel.properties['return'] = constrainedObjectPropertyModel2;
+    const constrainedKey = GoDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, objectPropertyModel: objectPropertyModel2, constrainedObjectPropertyModel: constrainedObjectPropertyModel2});
+    expect(constrainedKey).toEqual('ReservedReservedReturn');
   });
   test('should never render reserved keywords', () => {
     const constrainedKey = constrainPropertyName('return');
@@ -42,17 +45,16 @@ describe('PropertyKeyConstrainer', () => {
   });
   describe('custom constraints', () => {
     test('should be able to overwrite all hooks', () => {
-      const mockedConstraintCallbacks: PropertyKeyConstraintOptions = {
+      const mockedConstraintCallbacks: Partial<PropertyKeyConstraintOptions> = {
         NAMING_FORMATTER: jest.fn().mockReturnValue(''),
         NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
         NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
         NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
-        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue(''),
-        NO_DUPLICATE_PROPERTIES: jest.fn().mockReturnValue('')
+        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue('')
       };
       const constrainFunction = defaultPropertyKeyConstraints(mockedConstraintCallbacks);
       const objectPropertyModel = new ObjectPropertyModel('', false, objectModel);
-      const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', objectPropertyModel.required, constrainedObjectModel);
+      const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', '', objectPropertyModel.required, constrainedObjectModel);
       constrainFunction({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel});
       //Expect all callbacks to be called
       for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
@@ -71,7 +73,7 @@ describe('PropertyKeyConstrainer', () => {
       const jestCallback = jest.fn().mockReturnValue('');
       const constrainFunction = defaultPropertyKeyConstraints({NAMING_FORMATTER: jestCallback});
       const objectPropertyModel = new ObjectPropertyModel('', false, objectModel);
-      const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', objectPropertyModel.required, constrainedObjectModel);
+      const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', '', objectPropertyModel.required, constrainedObjectModel);
       const constrainedValue = constrainFunction({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel});
       expect(constrainedValue).toEqual('');
       for (const jestMockCallback of spies) {
diff --git a/test/generators/typescript/TypeScriptConstrainer.spec.ts b/test/generators/typescript/TypeScriptConstrainer.spec.ts
index d56c9416..0d883f81 100644
--- a/test/generators/typescript/TypeScriptConstrainer.spec.ts
+++ b/test/generators/typescript/TypeScriptConstrainer.spec.ts
@@ -1,16 +1,10 @@
 import {TypeScriptDefaultTypeMapping } from '../../../src/generators/typescript/TypeScriptConstrainer';
-import {MockTypeScriptRenderer} from '../../TestUtils/TestRenderers';
-import { TypeScriptRenderer } from '../../../src/generators/typescript/TypeScriptRenderer';
-import { CommonInputModel, CommonModel, ConstrainedAnyModel, ConstrainedArrayModel, ConstrainedBooleanModel, ConstrainedDictionaryModel, ConstrainedEnumModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedTupleValueModel, ConstrainedUnionModel, TypeScriptGenerator } from '../../../src';
+import { ConstrainedAnyModel, ConstrainedArrayModel, ConstrainedBooleanModel, ConstrainedDictionaryModel, ConstrainedEnumModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedTupleValueModel, ConstrainedUnionModel, TypeScriptGenerator } from '../../../src';
 describe('TypeScriptConstrainer', () => {
-  let renderer: TypeScriptRenderer;
-  beforeEach(() => {
-    renderer = new MockTypeScriptRenderer(TypeScriptGenerator.defaultOptions, new TypeScriptGenerator(), [], new CommonModel(), new CommonInputModel());
-  });
   describe('ObjectModel', () => { 
     test('should render the constrained name as type', () => {
       const model = new ConstrainedObjectModel('test', undefined, '', {});
-      const type = TypeScriptDefaultTypeMapping.Object({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Object({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual(model.name);
     });
   });
@@ -18,42 +12,42 @@ describe('TypeScriptConstrainer', () => {
     test('should render the constrained name as type', () => {
       const refModel = new ConstrainedAnyModel('test', undefined, '');
       const model = new ConstrainedReferenceModel('test', undefined, '', refModel);
-      const type = TypeScriptDefaultTypeMapping.Reference({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Reference({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual(model.name);
     });
   });
   describe('Any', () => { 
     test('should render type', () => {
       const model = new ConstrainedAnyModel('test', undefined, '');
-      const type = TypeScriptDefaultTypeMapping.Any({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Any({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('any');
     });
   });
   describe('Float', () => { 
     test('should render type', () => {
       const model = new ConstrainedFloatModel('test', undefined, '');
-      const type = TypeScriptDefaultTypeMapping.Float({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Float({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('number');
     });
   });
   describe('Integer', () => { 
     test('should render type', () => {
       const model = new ConstrainedIntegerModel('test', undefined, '');
-      const type = TypeScriptDefaultTypeMapping.Integer({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Integer({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('integer');
     });
   });
   describe('String', () => { 
     test('should render type', () => {
       const model = new ConstrainedStringModel('test', undefined, '');
-      const type = TypeScriptDefaultTypeMapping.String({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.String({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('string');
     });
   });
   describe('Boolean', () => { 
     test('should render type', () => {
       const model = new ConstrainedBooleanModel('test', undefined, '');
-      const type = TypeScriptDefaultTypeMapping.Boolean({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Boolean({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('boolean');
     });
   });
@@ -63,7 +57,7 @@ describe('TypeScriptConstrainer', () => {
       const stringModel = new ConstrainedStringModel('test', undefined, 'String');
       const tupleValueModel = new ConstrainedTupleValueModel(0, stringModel);
       const model = new ConstrainedTupleModel('test', undefined, '', [tupleValueModel]);
-      const type = TypeScriptDefaultTypeMapping.Tuple({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Tuple({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('[String]');
     });
     test('should render multiple tuple types', () => {
@@ -71,7 +65,7 @@ describe('TypeScriptConstrainer', () => {
       const tupleValueModel0 = new ConstrainedTupleValueModel(0, stringModel);
       const tupleValueModel1 = new ConstrainedTupleValueModel(1, stringModel);
       const model = new ConstrainedTupleModel('test', undefined, '', [tupleValueModel0, tupleValueModel1]);
-      const type = TypeScriptDefaultTypeMapping.Tuple({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Tuple({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('[String, String]');
     });
   });
@@ -80,7 +74,7 @@ describe('TypeScriptConstrainer', () => {
     test('should render type', () => {
       const arrayModel = new ConstrainedStringModel('test', undefined, 'String');
       const model = new ConstrainedArrayModel('test', undefined, '', arrayModel);
-      const type = TypeScriptDefaultTypeMapping.Array({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Array({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('String[]');
     });
   });
@@ -88,7 +82,7 @@ describe('TypeScriptConstrainer', () => {
   describe('Enum', () => { 
     test('should render the constrained name as type', () => {
       const model = new ConstrainedEnumModel('test', undefined, '', []);
-      const type = TypeScriptDefaultTypeMapping.Enum({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Enum({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual(model.name);
     });
   });
@@ -97,32 +91,46 @@ describe('TypeScriptConstrainer', () => {
     test('should render type', () => {
       const unionModel = new ConstrainedStringModel('test', undefined, 'String');
       const model = new ConstrainedUnionModel('test', undefined, '', [unionModel]);
-      const type = TypeScriptDefaultTypeMapping.Union({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Union({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('String');
     });
     test('should render multiple types', () => {
       const unionModel1 = new ConstrainedStringModel('test', undefined, 'String');
       const unionModel2 = new ConstrainedStringModel('test', undefined, 'String');
       const model = new ConstrainedUnionModel('test', undefined, '', [unionModel1, unionModel2]);
-      const type = TypeScriptDefaultTypeMapping.Union({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Union({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
       expect(type).toEqual('String | String');
     });
   });
 
   describe('Dictionary', () => { 
-    test('should render type', () => {
+    test('should render type with default map type', () => {
+      const keyModel = new ConstrainedStringModel('test', undefined, 'String');
+      const valueModel = new ConstrainedStringModel('test', undefined, 'String');
+      const model = new ConstrainedDictionaryModel('test', undefined, '', keyModel, valueModel);
+      const type = TypeScriptDefaultTypeMapping.Dictionary({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
+      expect(type).toEqual('Map<String, String>');
+    });
+    test('should render type with indexed object map type', () => {
       const keyModel = new ConstrainedStringModel('test', undefined, 'String');
       const valueModel = new ConstrainedStringModel('test', undefined, 'String');
       const model = new ConstrainedDictionaryModel('test', undefined, '', keyModel, valueModel);
-      const type = TypeScriptDefaultTypeMapping.Dictionary({constrainedModel: model, renderer});
+      const type = TypeScriptDefaultTypeMapping.Dictionary({constrainedModel: model, options: {...TypeScriptGenerator.defaultOptions, mapType: 'indexedObject'}});
       expect(type).toEqual('{ [name: String]: String }');
     });
+    test('should render type with record map type', () => {
+      const keyModel = new ConstrainedStringModel('test', undefined, 'String');
+      const valueModel = new ConstrainedStringModel('test', undefined, 'String');
+      const model = new ConstrainedDictionaryModel('test', undefined, '', keyModel, valueModel);
+      const type = TypeScriptDefaultTypeMapping.Dictionary({constrainedModel: model, options: {...TypeScriptGenerator.defaultOptions, mapType: 'record'}});
+      expect(type).toEqual('Record<String, String>');
+    });
     test('should not be able to render dictionary with union key type', () => {
       const keyModel = new ConstrainedUnionModel('test', undefined, 'String', []);
       const valueModel = new ConstrainedStringModel('test', undefined, 'String');
       const model = new ConstrainedDictionaryModel('test', undefined, '', keyModel, valueModel);
-      const type = TypeScriptDefaultTypeMapping.Dictionary({constrainedModel: model, renderer});
-      expect(type).toEqual('{ [name: any]: String }');
+      const type = TypeScriptDefaultTypeMapping.Dictionary({constrainedModel: model, options: TypeScriptGenerator.defaultOptions});
+      expect(type).toEqual('Map<any, String>');
     });
   });
 });
diff --git a/test/generators/typescript/TypeScriptGenerator.spec.ts b/test/generators/typescript/TypeScriptGenerator.spec.ts
index 393c78d3..94acd7d5 100644
--- a/test/generators/typescript/TypeScriptGenerator.spec.ts
+++ b/test/generators/typescript/TypeScriptGenerator.spec.ts
@@ -16,33 +16,10 @@ describe('TypeScriptGenerator', () => {
       },
       additionalProperties: false
     };
-    const expected = `class Address {
-  private _reservedReservedEnum?: string;
-  private _reservedEnum?: string;
-
-  constructor(input: {
-    reservedReservedEnum?: string,
-    reservedEnum?: string,
-  }) {
-    this._reservedReservedEnum = input.reservedReservedEnum;
-    this._reservedEnum = input.reservedEnum;
-  }
-
-  get reservedReservedEnum(): string | undefined { return this._reservedReservedEnum; }
-  set reservedReservedEnum(reservedReservedEnum: string | undefined) { this._reservedReservedEnum = reservedReservedEnum; }
-
-  get reservedEnum(): string | undefined { return this._reservedEnum; }
-  set reservedEnum(reservedEnum: string | undefined) { this._reservedEnum = reservedEnum; }
-}`;
-
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['Address'];
-
-    let classModel = await generator.renderClass(model, inputModel);
-    expect(classModel.result).toEqual(expected);
-
-    classModel = await generator.render(model, inputModel);
-    expect(classModel.result).toEqual(expected);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render `class` type', async () => {
@@ -67,85 +44,10 @@ describe('TypeScriptGenerator', () => {
       },
       required: ['street_name', 'city', 'state', 'house_number', 'array_type'],
     };
-    const expected = `class Address {
-  private _streetName: string;
-  private _city: string;
-  private _state: string;
-  private _houseNumber: number;
-  private _marriage?: boolean;
-  private _members?: string | number | boolean;
-  private _tupleType?: [string, number];
-  private _tupleTypeWithAdditionalItems?: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]];
-  private _arrayType: Array<string>;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
-  private _sTestPatternProperties?: Map<String, string>;
-
-  constructor(input: {
-    streetName: string,
-    city: string,
-    state: string,
-    houseNumber: number,
-    marriage?: boolean,
-    members?: string | number | boolean,
-    tupleType?: [string, number],
-    tupleTypeWithAdditionalItems?: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]],
-    arrayType: Array<string>,
-  }) {
-    this._streetName = input.streetName;
-    this._city = input.city;
-    this._state = input.state;
-    this._houseNumber = input.houseNumber;
-    this._marriage = input.marriage;
-    this._members = input.members;
-    this._tupleType = input.tupleType;
-    this._tupleTypeWithAdditionalItems = input.tupleTypeWithAdditionalItems;
-    this._arrayType = input.arrayType;
-  }
-
-  get streetName(): string { return this._streetName; }
-  set streetName(streetName: string) { this._streetName = streetName; }
-
-  get city(): string { return this._city; }
-  set city(city: string) { this._city = city; }
-
-  get state(): string { return this._state; }
-  set state(state: string) { this._state = state; }
-
-  get houseNumber(): number { return this._houseNumber; }
-  set houseNumber(houseNumber: number) { this._houseNumber = houseNumber; }
-
-  get marriage(): boolean | undefined { return this._marriage; }
-  set marriage(marriage: boolean | undefined) { this._marriage = marriage; }
-
-  get members(): string | number | boolean | undefined { return this._members; }
-  set members(members: string | number | boolean | undefined) { this._members = members; }
-
-  get tupleType(): [string, number] | undefined { return this._tupleType; }
-  set tupleType(tupleType: [string, number] | undefined) { this._tupleType = tupleType; }
-
-  get tupleTypeWithAdditionalItems(): [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]] | undefined { return this._tupleTypeWithAdditionalItems; }
-  set tupleTypeWithAdditionalItems(tupleTypeWithAdditionalItems: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]] | undefined) { this._tupleTypeWithAdditionalItems = tupleTypeWithAdditionalItems; }
-
-  get arrayType(): Array<string> { return this._arrayType; }
-  set arrayType(arrayType: Array<string>) { this._arrayType = arrayType; }
-
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
-
-  get sTestPatternProperties(): Map<String, string> | undefined { return this._sTestPatternProperties; }
-  set sTestPatternProperties(sTestPatternProperties: Map<String, string> | undefined) { this._sTestPatternProperties = sTestPatternProperties; }
-}`;
-
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['_address'];
-
-    let classModel = await generator.renderClass(model, inputModel);
-    expect(classModel.result).toEqual(expected);
-    expect(classModel.dependencies).toEqual([]);
-
-    classModel = await generator.render(model, inputModel);
-    expect(classModel.result).toEqual(expected);
-    expect(classModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should work custom preset for `class` type', async () => {
@@ -156,31 +58,13 @@ describe('TypeScriptGenerator', () => {
         property: { type: 'string' },
       }
     };
-    const expected = `class CustomClass {
-  @JsonProperty("property")
-  private _property?: string;
-  @JsonProperty("additionalProperties")
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
-
-  constructor(input: {
-    property?: string,
-  }) {
-    this._property = input.property;
-  }
-
-  get property(): string | undefined { return this._property; }
-  set property(property: string | undefined) { this._property = property; }
-
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
-}`;
 
     generator = new TypeScriptGenerator({
       presets: [
         {
           class: {
-            property({ propertyName, content }) {
-              return `@JsonProperty("${propertyName}")
+            property({ property, content }) {
+              return `@JsonProperty("${property.propertyName}")
 ${content}`;
             },
           }
@@ -188,12 +72,10 @@ ${content}`;
       ]
     });
 
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['CustomClass'];
-
-    const classModel = await generator.render(model, inputModel);
-    expect(classModel.result).toEqual(expected);
-    expect(classModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render `interface` type', async () => {
@@ -218,27 +100,12 @@ ${content}`;
       },
       required: ['street_name', 'city', 'state', 'house_number', 'array_type'],
     };
-    const expected = `interface Address {
-  streetName: string;
-  city: string;
-  state: string;
-  houseNumber: number;
-  marriage?: boolean;
-  members?: string | number | boolean;
-  tupleType?: [string, number];
-  tupleTypeWithAdditionalItems?: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]];
-  arrayType: Array<string>;
-  additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
-  sTestPatternProperties?: Map<String, string>;
-}`;
-
-    const interfaceGenerator = new TypeScriptGenerator({ modelType: 'interface' });
-    const inputModel = await interfaceGenerator.process(doc);
-    const model = inputModel.models['Address'];
 
-    const interfaceModel = await interfaceGenerator.render(model, inputModel);
-    expect(interfaceModel.result).toEqual(expected);
-    expect(interfaceModel.dependencies).toEqual([]);
+    generator = new TypeScriptGenerator({ modelType: 'interface' });
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should work custom preset for `interface` type', async () => {
@@ -266,12 +133,10 @@ ${content}`;
       ]
     });
 
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['CustomInterface'];
-
-    const interfaceModel = await generator.renderInterface(model, inputModel);
-    expect(interfaceModel.result).toEqual(expected);
-    expect(interfaceModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render `enum` type', async () => {
@@ -280,22 +145,10 @@ ${content}`;
       type: 'string',
       enum: ['Texas', 'Alabama', 'California'],
     };
-    const expected = `enum States {
-  TEXAS = "Texas",
-  ALABAMA = "Alabama",
-  CALIFORNIA = "California",
-}`;
-
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['States'];
-
-    let enumModel = await generator.render(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
-
-    enumModel = await generator.renderEnum(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render `enum` type as `union` if option enumType = `union`', async () => {
@@ -306,17 +159,11 @@ ${content}`;
     };
     const expected = 'type States = "Texas" | "Alabama" | "California";';
 
-    const unionGenerator = new TypeScriptGenerator({ enumType: 'union' });
-    const inputModel = await unionGenerator.process(doc);
-    const model = inputModel.models['States'];
-
-    let enumModel = await unionGenerator.render(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
-
-    enumModel = await unionGenerator.renderType(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
+    generator = new TypeScriptGenerator({ enumType: 'union' });
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render union `enum` values', async () => {
@@ -331,17 +178,10 @@ ${content}`;
   TRUE = "true",
   TEST_TEST = '{"test":"test"}',
 }`;
-
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['States'];
-
-    let enumModel = await generator.render(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
-
-    enumModel = await generator.renderEnum(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render enums with translated special characters', async () => {
@@ -349,24 +189,11 @@ ${content}`;
       $id: 'States',
       enum: ['test+', 'test', 'test-', 'test?!', '*test']
     };
-    const expected = `enum States {
-  TEST_PLUS = "test+",
-  TEST = "test",
-  TEST_MINUS = "test-",
-  TEST_QUESTION_EXCLAMATION = "test?!",
-  ASTERISK_TEST = "*test",
-}`;
-
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['States'];
-
-    let enumModel = await generator.render(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
-
-    enumModel = await generator.renderEnum(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
+    
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should work custom preset for `enum` type', async () => {
@@ -375,11 +202,6 @@ ${content}`;
       type: 'string',
       enum: ['Texas', 'Alabama', 'California'],
     };
-    const expected = `enum CustomEnum {
-  TEXAS = "Texas",
-  ALABAMA = "Alabama",
-  CALIFORNIA = "California",
-}`;
 
     generator = new TypeScriptGenerator({
       presets: [
@@ -393,16 +215,10 @@ ${content}`;
       ]
     });
 
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['CustomEnum'];
-
-    let enumModel = await generator.render(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
-
-    enumModel = await generator.renderEnum(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render `type` type - primitive', async () => {
@@ -410,18 +226,11 @@ ${content}`;
       $id: 'TypePrimitive',
       type: 'string',
     };
-    const expected = 'type TypePrimitive = string;';
-
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['TypePrimitive'];
 
-    let primitiveModel = await generator.renderType(model, inputModel);
-    expect(primitiveModel.result).toEqual(expected);
-    expect(primitiveModel.dependencies).toEqual([]);
-
-    primitiveModel = await generator.render(model, inputModel);
-    expect(primitiveModel.result).toEqual(expected);
-    expect(primitiveModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render `type` type - enum', async () => {
@@ -429,14 +238,11 @@ ${content}`;
       $id: 'TypeEnum',
       enum: ['Texas', 'Alabama', 'California', 0, 1, false, true],
     };
-    const expected = 'type TypeEnum = "Texas" | "Alabama" | "California" | 0 | 1 | false | true;';
-
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['TypeEnum'];
-
-    const enumModel = await generator.renderType(model, inputModel);
-    expect(enumModel.result).toEqual(expected);
-    expect(enumModel.dependencies).toEqual([]);
+    
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render `type` type - union', async () => {
@@ -444,14 +250,11 @@ ${content}`;
       $id: 'TypeUnion',
       type: ['string', 'number', 'boolean'],
     };
-    const expected = 'type TypeUnion = string | number | boolean;';
-
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['TypeUnion'];
-
-    const unionModel = await generator.renderType(model, inputModel);
-    expect(unionModel.result).toEqual(expected);
-    expect(unionModel.dependencies).toEqual([]);
+    
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render `type` type - array of primitive type', async () => {
@@ -463,14 +266,11 @@ ${content}`;
         type: 'string',
       }
     };
-    const expected = 'type TypeArray = Array<string>;';
-
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['TypeArray'];
 
-    const arrayModel = await generator.renderType(model, inputModel);
-    expect(arrayModel.result).toEqual(expected);
-    expect(arrayModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   test('should render `type` type - array of union type', async () => {
@@ -483,12 +283,10 @@ ${content}`;
       }
     };
 
-    const inputModel = await generator.process(doc);
-    const model = inputModel.models['TypeArray'];
-
-    const arrayModel = await generator.renderType(model, inputModel);
-    expect(arrayModel.result).toMatchSnapshot();
-    expect(arrayModel.dependencies).toEqual([]);
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(1);
+    expect(models[0].result).toMatchSnapshot();
+    expect(models[0].dependencies).toEqual([]);
   });
 
   const doc = {
diff --git a/test/generators/typescript/TypeScriptRenderer.spec.ts b/test/generators/typescript/TypeScriptRenderer.spec.ts
index 3a07db5e..2a20d40f 100644
--- a/test/generators/typescript/TypeScriptRenderer.spec.ts
+++ b/test/generators/typescript/TypeScriptRenderer.spec.ts
@@ -1,35 +1,12 @@
-import { defaultGeneratorOptions, TypeScriptGenerator } from '../../../src/generators';
+import { ConstrainedObjectModel, InputMetaModel } from '../../../src';
+import { TypeScriptGenerator } from '../../../src/generators';
 import { TypeScriptRenderer } from '../../../src/generators/typescript/TypeScriptRenderer';
-import { CommonInputModel, CommonModel } from '../../../src/models';
-class MockTypeScriptRenderer extends TypeScriptRenderer {
+import { MockTypeScriptRenderer } from '../../TestUtils/TestRenderers';
 
-}
 describe('TypeScriptRenderer', () => {
-  let renderer: TypeScriptRenderer;
+  let renderer: TypeScriptRenderer<any>;
   beforeEach(() => {
-    renderer = new MockTypeScriptRenderer(TypeScriptGenerator.defaultOptions, new TypeScriptGenerator(), [], new CommonModel(), new CommonInputModel());
-  });
-
-  describe('nameType()', () => {
-    test('should name the type', () => {
-      const name = renderer.nameType('type__someType');
-      expect(name).toEqual('TypeSomeType');
-    });
-    test('should render reserved type keyword correctly', () => {
-      const name = renderer.nameType('enum');
-      expect(name).toEqual('Enum');
-    });
-  });
-  
-  describe('nameProperty()', () => {
-    test('should name the property', () => {
-      const name = renderer.nameProperty('property__someProperty');
-      expect(name).toEqual('propertySomeProperty');
-    });
-    test('should render reserved property keyword correctly', () => {
-      const name = renderer.nameProperty('enum');
-      expect(name).toEqual('reservedEnum');
-    });
+    renderer = new MockTypeScriptRenderer(TypeScriptGenerator.defaultOptions, new TypeScriptGenerator(), [], new ConstrainedObjectModel('', undefined, '', {}), new InputMetaModel());
   });
 
   describe('renderComments()', () => {
@@ -39,67 +16,4 @@ describe('TypeScriptRenderer', () => {
  */`);
     });
   });
-
-  describe('toTsType()', () => {
-    test('should not render duplicate types', () => {
-      expect(renderer.toTsType(undefined, new CommonModel())).toEqual('any');
-    });
-    test('Should render unknown type', () => {
-      expect(renderer.toTsType(undefined, new CommonModel())).toEqual('any');
-    });
-    test('Should render number type', () => {
-      expect(renderer.toTsType('number', new CommonModel())).toEqual('number');
-    });
-    test('Should render object type', () => {
-      expect(renderer.toTsType('object', new CommonModel())).toEqual('object');
-    });
-    test('Should render null type', () => {
-      expect(renderer.toTsType('null', new CommonModel())).toEqual('null');
-    });
-    test('Should render array type', () => {
-      const model = new CommonModel();
-      model.items = CommonModel.toCommonModel({type: 'number'});
-      expect(renderer.toTsType('array', model)).toEqual('Array<number>');
-    });
-    test('Should render tuple type', () => {
-      const model = new CommonModel();
-      model.items = [CommonModel.toCommonModel({type: 'number'})];
-      expect(renderer.toTsType('array', model)).toEqual('[number]');
-    });
-    test('Should render tuple type with additionalItems', () => {
-      const model = new CommonModel();
-      model.items = [CommonModel.toCommonModel({type: 'number'})];
-      model.additionalItems = CommonModel.toCommonModel({type: 'string'});
-      expect(renderer.toTsType('array', model)).toEqual('[number, ...(string)[]]');
-    });
-    test('Should render multiple tuples', () => {
-      const model = new CommonModel();
-      model.items = [CommonModel.toCommonModel({type: 'number'}), CommonModel.toCommonModel({type: 'string'})];
-      expect(renderer.toTsType('array', model)).toEqual('[number, string]');
-    });
-  });
-  describe('renderType()', () => {
-    test('Should render refs with pascal case', () => {
-      const model = new CommonModel();
-      model.$ref = '<anonymous-schema-1>';
-      expect(renderer.renderType(model)).toEqual('AnonymousSchema_1');
-    });
-    test('Should render array of CommonModels', () => {
-      const model1 = new CommonModel();
-      model1.$ref = 'ref1';
-      const model2 = new CommonModel();
-      model2.$ref = 'ref2';
-      expect(renderer.renderType([model1, model2])).toEqual('Ref1 | Ref2');
-    });
-    test('Should render enums', () => {
-      const model = new CommonModel();
-      model.enum = ['enum1', 'enum2', 9];
-      expect(renderer.renderType(model)).toEqual('"enum1" | "enum2" | 9');
-    });
-    test('should not render duplicate types', () => {
-      const model = new CommonModel();
-      model.type = ['integer', 'number'];
-      expect(renderer.renderType(model)).toEqual('number');
-    });
-  });
 });
diff --git a/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap b/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap
index 79eb6ee6..344929c1 100644
--- a/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap
+++ b/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap
@@ -1,10 +1,152 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`TypeScriptGenerator should render \`type\` type - array of union type 1`] = `"type TypeArray = Array<string | number | boolean>;"`;
+exports[`TypeScriptGenerator should not render \`class\` with reserved keyword 1`] = `
+"class Address {
+  private _reservedReservedEnum?: string;
+  private _reservedEnum?: string;
+
+  constructor(input: {
+    reservedReservedEnum?: string,
+    reservedEnum?: string,
+  }) {
+    this._reservedReservedEnum = input.reservedReservedEnum;
+    this._reservedEnum = input.reservedEnum;
+  }
+
+  get reservedReservedEnum(): string | undefined { return this._reservedReservedEnum; }
+  set reservedReservedEnum(reservedReservedEnum: string | undefined) { this._reservedReservedEnum = reservedReservedEnum; }
+
+  get reservedEnum(): string | undefined { return this._reservedEnum; }
+  set reservedEnum(reservedEnum: string | undefined) { this._reservedEnum = reservedEnum; }
+}"
+`;
+
+exports[`TypeScriptGenerator should render \`class\` type 1`] = `
+"class Address {
+  private _streetName: string;
+  private _city: string;
+  private _state: string;
+  private _houseNumber: number;
+  private _marriage?: boolean;
+  private _members?: string | number | boolean;
+  private _tupleType?: [string, number];
+  private _tupleTypeWithAdditionalItems?: string | number | any[];
+  private _arrayType: string | any[];
+  private _additionalProperties?: Map<string, any>;
+
+  constructor(input: {
+    streetName: string,
+    city: string,
+    state: string,
+    houseNumber: number,
+    marriage?: boolean,
+    members?: string | number | boolean,
+    tupleType?: [string, number],
+    tupleTypeWithAdditionalItems?: string | number | any[],
+    arrayType: string | any[],
+    additionalProperties?: Map<string, any>,
+  }) {
+    this._streetName = input.streetName;
+    this._city = input.city;
+    this._state = input.state;
+    this._houseNumber = input.houseNumber;
+    this._marriage = input.marriage;
+    this._members = input.members;
+    this._tupleType = input.tupleType;
+    this._tupleTypeWithAdditionalItems = input.tupleTypeWithAdditionalItems;
+    this._arrayType = input.arrayType;
+    this._additionalProperties = input.additionalProperties;
+  }
+
+  get streetName(): string { return this._streetName; }
+  set streetName(streetName: string) { this._streetName = streetName; }
+
+  get city(): string { return this._city; }
+  set city(city: string) { this._city = city; }
+
+  get state(): string { return this._state; }
+  set state(state: string) { this._state = state; }
+
+  get houseNumber(): number { return this._houseNumber; }
+  set houseNumber(houseNumber: number) { this._houseNumber = houseNumber; }
+
+  get marriage(): boolean | undefined { return this._marriage; }
+  set marriage(marriage: boolean | undefined) { this._marriage = marriage; }
+
+  get members(): string | number | boolean | undefined { return this._members; }
+  set members(members: string | number | boolean | undefined) { this._members = members; }
+
+  get tupleType(): [string, number] | undefined { return this._tupleType; }
+  set tupleType(tupleType: [string, number] | undefined) { this._tupleType = tupleType; }
+
+  get tupleTypeWithAdditionalItems(): string | number | any[] | undefined { return this._tupleTypeWithAdditionalItems; }
+  set tupleTypeWithAdditionalItems(tupleTypeWithAdditionalItems: string | number | any[] | undefined) { this._tupleTypeWithAdditionalItems = tupleTypeWithAdditionalItems; }
+
+  get arrayType(): string | any[] { return this._arrayType; }
+  set arrayType(arrayType: string | any[]) { this._arrayType = arrayType; }
+
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
+}"
+`;
+
+exports[`TypeScriptGenerator should render \`enum\` type 1`] = `
+"enum States {
+  TEXAS = \\"Texas\\",
+  ALABAMA = \\"Alabama\\",
+  CALIFORNIA = \\"California\\",
+}"
+`;
+
+exports[`TypeScriptGenerator should render \`enum\` type as \`union\` if option enumType = \`union\` 1`] = `"type States = States;"`;
+
+exports[`TypeScriptGenerator should render \`interface\` type 1`] = `
+"interface Address {
+  streetName: string;
+  city: string;
+  state: string;
+  houseNumber: number;
+  marriage?: boolean;
+  members?: string | number | boolean;
+  tupleType?: [string, number];
+  tupleTypeWithAdditionalItems?: string | number | any[];
+  arrayType: string | any[];
+  additionalProperties?: Map<string, any>;
+}"
+`;
+
+exports[`TypeScriptGenerator should render \`type\` type - array of primitive type 1`] = `"type TypeArray = string | any[];"`;
+
+exports[`TypeScriptGenerator should render \`type\` type - array of union type 1`] = `"type TypeArray = string | number | boolean | any[];"`;
+
+exports[`TypeScriptGenerator should render \`type\` type - enum 1`] = `
+"enum TypeEnum {
+  TEXAS = \\"Texas\\",
+  ALABAMA = \\"Alabama\\",
+  CALIFORNIA = \\"California\\",
+  NUMBER_0 = 0,
+  NUMBER_1 = 1,
+  RESERVED_FALSE = \\"false\\",
+  RESERVED_TRUE = \\"true\\",
+}"
+`;
+
+exports[`TypeScriptGenerator should render \`type\` type - primitive 1`] = `"type TypePrimitive = string;"`;
+
+exports[`TypeScriptGenerator should render \`type\` type - union 1`] = `"type TypeUnion = string | number | boolean;"`;
+
+exports[`TypeScriptGenerator should render enums with translated special characters 1`] = `
+"enum States {
+  TEST_PLUS = \\"test+\\",
+  TEST = \\"test\\",
+  TEST_MINUS = \\"test-\\",
+  TEST_QUESTION_EXCLAMATION = \\"test?!\\",
+  ASTERISK_TEST = \\"*test\\",
+}"
+`;
 
 exports[`TypeScriptGenerator should render models and their dependencies for CJS module system 1`] = `
 "const OtherModel = require('./OtherModel');
-
 class Address {
   private _streetName: string;
   private _city: string;
@@ -12,10 +154,9 @@ class Address {
   private _houseNumber: number;
   private _marriage?: boolean;
   private _members?: string | number | boolean;
-  private _arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]];
+  private _arrayType: string | number | any[];
   private _otherModel?: OtherModel;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
-  private _sTestPatternProperties?: Map<String, string>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     streetName: string,
@@ -24,8 +165,9 @@ class Address {
     houseNumber: number,
     marriage?: boolean,
     members?: string | number | boolean,
-    arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]],
+    arrayType: string | number | any[],
     otherModel?: OtherModel,
+    additionalProperties?: Map<string, any>,
   }) {
     this._streetName = input.streetName;
     this._city = input.city;
@@ -35,6 +177,7 @@ class Address {
     this._members = input.members;
     this._arrayType = input.arrayType;
     this._otherModel = input.otherModel;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get streetName(): string { return this._streetName; }
@@ -55,46 +198,43 @@ class Address {
   get members(): string | number | boolean | undefined { return this._members; }
   set members(members: string | number | boolean | undefined) { this._members = members; }
 
-  get arrayType(): [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]] { return this._arrayType; }
-  set arrayType(arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]]) { this._arrayType = arrayType; }
+  get arrayType(): string | number | any[] { return this._arrayType; }
+  set arrayType(arrayType: string | number | any[]) { this._arrayType = arrayType; }
 
   get otherModel(): OtherModel | undefined { return this._otherModel; }
   set otherModel(otherModel: OtherModel | undefined) { this._otherModel = otherModel; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
-
-  get sTestPatternProperties(): Map<String, string> | undefined { return this._sTestPatternProperties; }
-  set sTestPatternProperties(sTestPatternProperties: Map<String, string> | undefined) { this._sTestPatternProperties = sTestPatternProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }
 module.exports = Address;"
 `;
 
 exports[`TypeScriptGenerator should render models and their dependencies for CJS module system 2`] = `
 "
-
 class OtherModel {
   private _streetName?: string;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     streetName?: string,
+    additionalProperties?: Map<string, any>,
   }) {
     this._streetName = input.streetName;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get streetName(): string | undefined { return this._streetName; }
   set streetName(streetName: string | undefined) { this._streetName = streetName; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }
 module.exports = OtherModel;"
 `;
 
 exports[`TypeScriptGenerator should render models and their dependencies for CJS module system with named exports 1`] = `
 "const {OtherModel} = require('./OtherModel');
-
 class Address {
   private _streetName: string;
   private _city: string;
@@ -102,10 +242,9 @@ class Address {
   private _houseNumber: number;
   private _marriage?: boolean;
   private _members?: string | number | boolean;
-  private _arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]];
+  private _arrayType: string | number | any[];
   private _otherModel?: OtherModel;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
-  private _sTestPatternProperties?: Map<String, string>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     streetName: string,
@@ -114,8 +253,9 @@ class Address {
     houseNumber: number,
     marriage?: boolean,
     members?: string | number | boolean,
-    arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]],
+    arrayType: string | number | any[],
     otherModel?: OtherModel,
+    additionalProperties?: Map<string, any>,
   }) {
     this._streetName = input.streetName;
     this._city = input.city;
@@ -125,6 +265,7 @@ class Address {
     this._members = input.members;
     this._arrayType = input.arrayType;
     this._otherModel = input.otherModel;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get streetName(): string { return this._streetName; }
@@ -145,46 +286,43 @@ class Address {
   get members(): string | number | boolean | undefined { return this._members; }
   set members(members: string | number | boolean | undefined) { this._members = members; }
 
-  get arrayType(): [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]] { return this._arrayType; }
-  set arrayType(arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]]) { this._arrayType = arrayType; }
+  get arrayType(): string | number | any[] { return this._arrayType; }
+  set arrayType(arrayType: string | number | any[]) { this._arrayType = arrayType; }
 
   get otherModel(): OtherModel | undefined { return this._otherModel; }
   set otherModel(otherModel: OtherModel | undefined) { this._otherModel = otherModel; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
-
-  get sTestPatternProperties(): Map<String, string> | undefined { return this._sTestPatternProperties; }
-  set sTestPatternProperties(sTestPatternProperties: Map<String, string> | undefined) { this._sTestPatternProperties = sTestPatternProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }
 exports.Address = Address;"
 `;
 
 exports[`TypeScriptGenerator should render models and their dependencies for CJS module system with named exports 2`] = `
 "
-
 class OtherModel {
   private _streetName?: string;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     streetName?: string,
+    additionalProperties?: Map<string, any>,
   }) {
     this._streetName = input.streetName;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get streetName(): string | undefined { return this._streetName; }
   set streetName(streetName: string | undefined) { this._streetName = streetName; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }
 exports.OtherModel = OtherModel;"
 `;
 
 exports[`TypeScriptGenerator should render models and their dependencies for ESM module system 1`] = `
 "import OtherModel from './OtherModel';
-
 class Address {
   private _streetName: string;
   private _city: string;
@@ -192,10 +330,9 @@ class Address {
   private _houseNumber: number;
   private _marriage?: boolean;
   private _members?: string | number | boolean;
-  private _arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]];
+  private _arrayType: string | number | any[];
   private _otherModel?: OtherModel;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
-  private _sTestPatternProperties?: Map<String, string>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     streetName: string,
@@ -204,8 +341,9 @@ class Address {
     houseNumber: number,
     marriage?: boolean,
     members?: string | number | boolean,
-    arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]],
+    arrayType: string | number | any[],
     otherModel?: OtherModel,
+    additionalProperties?: Map<string, any>,
   }) {
     this._streetName = input.streetName;
     this._city = input.city;
@@ -215,6 +353,7 @@ class Address {
     this._members = input.members;
     this._arrayType = input.arrayType;
     this._otherModel = input.otherModel;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get streetName(): string { return this._streetName; }
@@ -235,17 +374,14 @@ class Address {
   get members(): string | number | boolean | undefined { return this._members; }
   set members(members: string | number | boolean | undefined) { this._members = members; }
 
-  get arrayType(): [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]] { return this._arrayType; }
-  set arrayType(arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]]) { this._arrayType = arrayType; }
+  get arrayType(): string | number | any[] { return this._arrayType; }
+  set arrayType(arrayType: string | number | any[]) { this._arrayType = arrayType; }
 
   get otherModel(): OtherModel | undefined { return this._otherModel; }
   set otherModel(otherModel: OtherModel | undefined) { this._otherModel = otherModel; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
-
-  get sTestPatternProperties(): Map<String, string> | undefined { return this._sTestPatternProperties; }
-  set sTestPatternProperties(sTestPatternProperties: Map<String, string> | undefined) { this._sTestPatternProperties = sTestPatternProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }
 export default Address;
 "
@@ -253,22 +389,23 @@ export default Address;
 
 exports[`TypeScriptGenerator should render models and their dependencies for ESM module system 2`] = `
 "
-
 class OtherModel {
   private _streetName?: string;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     streetName?: string,
+    additionalProperties?: Map<string, any>,
   }) {
     this._streetName = input.streetName;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get streetName(): string | undefined { return this._streetName; }
   set streetName(streetName: string | undefined) { this._streetName = streetName; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }
 export default OtherModel;
 "
@@ -276,7 +413,6 @@ export default OtherModel;
 
 exports[`TypeScriptGenerator should render models and their dependencies for ESM module system with named exports 1`] = `
 "import {OtherModel} from './OtherModel';
-
 export class Address {
   private _streetName: string;
   private _city: string;
@@ -284,10 +420,9 @@ export class Address {
   private _houseNumber: number;
   private _marriage?: boolean;
   private _members?: string | number | boolean;
-  private _arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]];
+  private _arrayType: string | number | any[];
   private _otherModel?: OtherModel;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
-  private _sTestPatternProperties?: Map<String, string>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     streetName: string,
@@ -296,8 +431,9 @@ export class Address {
     houseNumber: number,
     marriage?: boolean,
     members?: string | number | boolean,
-    arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]],
+    arrayType: string | number | any[],
     otherModel?: OtherModel,
+    additionalProperties?: Map<string, any>,
   }) {
     this._streetName = input.streetName;
     this._city = input.city;
@@ -307,6 +443,7 @@ export class Address {
     this._members = input.members;
     this._arrayType = input.arrayType;
     this._otherModel = input.otherModel;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get streetName(): string { return this._streetName; }
@@ -327,39 +464,99 @@ export class Address {
   get members(): string | number | boolean | undefined { return this._members; }
   set members(members: string | number | boolean | undefined) { this._members = members; }
 
-  get arrayType(): [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]] { return this._arrayType; }
-  set arrayType(arrayType: [string, number, ...(object | string | number | Array<unknown> | boolean | null)[]]) { this._arrayType = arrayType; }
+  get arrayType(): string | number | any[] { return this._arrayType; }
+  set arrayType(arrayType: string | number | any[]) { this._arrayType = arrayType; }
 
   get otherModel(): OtherModel | undefined { return this._otherModel; }
   set otherModel(otherModel: OtherModel | undefined) { this._otherModel = otherModel; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
-
-  get sTestPatternProperties(): Map<String, string> | undefined { return this._sTestPatternProperties; }
-  set sTestPatternProperties(sTestPatternProperties: Map<String, string> | undefined) { this._sTestPatternProperties = sTestPatternProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }
 "
 `;
 
 exports[`TypeScriptGenerator should render models and their dependencies for ESM module system with named exports 2`] = `
 "
-
 export class OtherModel {
   private _streetName?: string;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     streetName?: string,
+    additionalProperties?: Map<string, any>,
   }) {
     this._streetName = input.streetName;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get streetName(): string | undefined { return this._streetName; }
   set streetName(streetName: string | undefined) { this._streetName = streetName; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }
 "
 `;
+
+exports[`TypeScriptGenerator should render union \`enum\` values 1`] = `
+"enum States {
+  NUMBER_2 = 2,
+  RESERVED_NUMBER_2 = \\"2\\",
+  TEST = \\"test\\",
+  RESERVED_TRUE = \\"true\\",
+  CURLYLEFT_QUOTATION_TEST_QUOTATION_COLON_QUOTATION_TEST_QUOTATION_CURLYRIGHT = '{\\"test\\":\\"test\\"}',
+}"
+`;
+
+exports[`TypeScriptGenerator should work custom preset for \`class\` type 1`] = `
+"class CustomClass {
+  @JsonProperty(\\"property\\")
+  private _property?: string;
+  @JsonProperty(\\"additionalProperties\\")
+  private _additionalProperties?: Map<string, any>;
+
+  constructor(input: {
+    property?: string,
+    additionalProperties?: Map<string, any>,
+  }) {
+    this._property = input.property;
+    this._additionalProperties = input.additionalProperties;
+  }
+
+  get property(): string | undefined { return this._property; }
+  set property(property: string | undefined) { this._property = property; }
+
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
+}"
+`;
+
+exports[`TypeScriptGenerator should work custom preset for \`enum\` type 1`] = `
+"enum CustomEnum {
+  TEXAS = \\"Texas\\",
+  ALABAMA = \\"Alabama\\",
+  CALIFORNIA = \\"California\\",
+}"
+`;
+
+exports[`TypeScriptGenerator should work custom preset for \`interface\` type 1`] = `
+"class CustomInterface {
+  private _property?: string;
+  private _additionalProperties?: Map<string, any>;
+
+  constructor(input: {
+    property?: string,
+    additionalProperties?: Map<string, any>,
+  }) {
+    this._property = input.property;
+    this._additionalProperties = input.additionalProperties;
+  }
+
+  get property(): string | undefined { return this._property; }
+  set property(property: string | undefined) { this._property = property; }
+
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
+}"
+`;
diff --git a/test/generators/typescript/constrainer/EnumConstrainer.spec.ts b/test/generators/typescript/constrainer/EnumConstrainer.spec.ts
index 0ad2fdc8..6721c05b 100644
--- a/test/generators/typescript/constrainer/EnumConstrainer.spec.ts
+++ b/test/generators/typescript/constrainer/EnumConstrainer.spec.ts
@@ -16,10 +16,10 @@ describe('EnumConstrainer', () => {
       expect(constrainedKey).toEqual('NUMBER_1');
     });
     test('should not contain duplicate keys', () => {
-      const existingConstrainedEnumValueModel = new ConstrainedEnumValueModel('TEST', 'test');
+      const existingConstrainedEnumValueModel = new ConstrainedEnumValueModel('EMPTY', 'return');
       const constrainedEnumModel = new ConstrainedEnumModel('test', undefined, '', [existingConstrainedEnumValueModel]);
-      const constrainedKey = TypeScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'TEST'});
-      expect(constrainedKey).toEqual('RESERVED_TEST');
+      const constrainedKey = TypeScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: ''});
+      expect(constrainedKey).toEqual('RESERVED_EMPTY');
     });
     test('should never contain empty keys', () => {
       const constrainedKey = TypeScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: ''});
@@ -58,11 +58,10 @@ describe('EnumConstrainer', () => {
   });
   describe('custom constraints', () => {
     test('should be able to overwrite all hooks for enum key', () => {
-      const mockedConstraintCallbacks: ModelEnumKeyConstraints = {
+      const mockedConstraintCallbacks: Partial<ModelEnumKeyConstraints> = {
         NAMING_FORMATTER: jest.fn().mockReturnValue(''),
         NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
         NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
-        NO_DUPLICATE_KEYS: jest.fn().mockReturnValue(''),
         NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
         NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue('')
       };
diff --git a/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts b/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts
index 17a0e3e8..faa2e56b 100644
--- a/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts
+++ b/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts
@@ -7,52 +7,54 @@ describe('PropertyKeyConstrainer', () => {
 
   const constrainPropertyName = (propertyName: string) => {
     const objectPropertyModel = new ObjectPropertyModel(propertyName, false, objectModel);
-    const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', objectPropertyModel.required, constrainedObjectModel);
+    const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', '', objectPropertyModel.required, constrainedObjectModel);
     return TypeScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel });
   };
 
   test('should never render special chars', () => {
     const constrainedKey = constrainPropertyName('%');
-    expect(constrainedKey).toEqual('Percent');
+    expect(constrainedKey).toEqual('percent');
   });
   test('should not render number as start char', () => {
     const constrainedKey = constrainPropertyName('1');
-    expect(constrainedKey).toEqual('Number_1');
+    expect(constrainedKey).toEqual('number_1');
   });
   test('should never contain empty name', () => {
     const constrainedKey = constrainPropertyName('');
-    expect(constrainedKey).toEqual('Empty');
+    expect(constrainedKey).toEqual('empty');
   });
   test('should use constant naming format', () => {
     const constrainedKey = constrainPropertyName('some weird_value!"#2');
-    expect(constrainedKey).toEqual('SomeWeirdValueExclamationQuotationHash_2');
+    expect(constrainedKey).toEqual('someWeirdValueExclamationQuotationHash_2');
   });
   test('should not contain duplicate properties', () => {
     const objectModel = new ObjectModel('test', undefined, {});
     const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {});
-    const objectPropertyModel = new ObjectPropertyModel('SomeProperty', false, objectModel);
-    const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('SomeProperty', objectPropertyModel.required, constrainedObjectModel);
-    constrainedObjectModel.properties['SomeProperty'] = constrainedObjectPropertyModel;
-    const constrainedKey = TypeScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel});
-    expect(constrainedKey).toEqual('ReservedSomeProperty');
+    const objectPropertyModel = new ObjectPropertyModel('reservedReturn', false, objectModel);
+    const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('reservedReturn', '', objectPropertyModel.required, constrainedObjectModel);
+    const objectPropertyModel2 = new ObjectPropertyModel('return', false, objectModel);
+    const constrainedObjectPropertyModel2 = new ConstrainedObjectPropertyModel('return', '', objectPropertyModel.required, constrainedObjectModel);
+    constrainedObjectModel.properties['reservedReturn'] = constrainedObjectPropertyModel;
+    constrainedObjectModel.properties['return'] = constrainedObjectPropertyModel2;
+    const constrainedKey = TypeScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, objectPropertyModel: objectPropertyModel2, constrainedObjectPropertyModel: constrainedObjectPropertyModel2});
+    expect(constrainedKey).toEqual('reservedReservedReturn');
   });
   test('should never render reserved keywords', () => {
     const constrainedKey = constrainPropertyName('return');
-    expect(constrainedKey).toEqual('ReservedReturn');
+    expect(constrainedKey).toEqual('reservedReturn');
   });
   describe('custom constraints', () => {
     test('should be able to overwrite all hooks', () => {
-      const mockedConstraintCallbacks: PropertyKeyConstraintOptions = {
+      const mockedConstraintCallbacks: Partial<PropertyKeyConstraintOptions> = {
         NAMING_FORMATTER: jest.fn().mockReturnValue(''),
         NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
         NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
         NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
-        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue(''),
-        NO_DUPLICATE_PROPERTIES: jest.fn().mockReturnValue('')
+        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue('')
       };
       const constrainFunction = defaultPropertyKeyConstraints(mockedConstraintCallbacks);
       const objectPropertyModel = new ObjectPropertyModel('', false, objectModel);
-      const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', objectPropertyModel.required, constrainedObjectModel);
+      const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', '', objectPropertyModel.required, constrainedObjectModel);
       constrainFunction({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel});
       //Expect all callbacks to be called
       for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
@@ -71,7 +73,7 @@ describe('PropertyKeyConstrainer', () => {
       const jestCallback = jest.fn().mockReturnValue('');
       const constrainFunction = defaultPropertyKeyConstraints({NAMING_FORMATTER: jestCallback});
       const objectPropertyModel = new ObjectPropertyModel('', false, objectModel);
-      const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', objectPropertyModel.required, constrainedObjectModel);
+      const constrainedObjectPropertyModel = new ConstrainedObjectPropertyModel('', '', objectPropertyModel.required, constrainedObjectModel);
       const constrainedValue = constrainFunction({constrainedObjectModel, objectModel, objectPropertyModel, constrainedObjectPropertyModel});
       expect(constrainedValue).toEqual('');
       for (const jestMockCallback of spies) {
diff --git a/test/generators/typescript/preset/DescriptionPreset.spec.ts b/test/generators/typescript/preset/DescriptionPreset.spec.ts
index f5477d56..1ce17126 100644
--- a/test/generators/typescript/preset/DescriptionPreset.spec.ts
+++ b/test/generators/typescript/preset/DescriptionPreset.spec.ts
@@ -31,17 +31,9 @@ describe('Description generation', () => {
   });
 
   test('should render example function for model', async () => {
-    const inputModel = await generator.process(doc);
-    const testModel = inputModel.models['Test'];
-    const nestedTestModel = inputModel.models['NestedTest'];
-
-    const testClass = await generator.renderClass(testModel, inputModel);
-    const nestedTestClass = await generator.renderClass(
-      nestedTestModel,
-      inputModel
-    );
-
-    expect(testClass.result).toMatchSnapshot();
-    expect(nestedTestClass.result).toMatchSnapshot();
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(2);
+    expect(models[0].result).toMatchSnapshot(); 
+    expect(models[1].result).toMatchSnapshot(); 
   });
 });
diff --git a/test/generators/typescript/preset/ExamplePreset.spec.ts b/test/generators/typescript/preset/ExamplePreset.spec.ts
index c38b8c02..347463ab 100644
--- a/test/generators/typescript/preset/ExamplePreset.spec.ts
+++ b/test/generators/typescript/preset/ExamplePreset.spec.ts
@@ -27,14 +27,9 @@ describe('Example function generation', () => {
         }
       ]
     });
-    const inputModel = await generator.process(doc);
-    const testModel = inputModel.models['Test'];
-    const nestedTestModel = inputModel.models['NestedTest'];
-
-    const testClass = await generator.renderClass(testModel, inputModel);
-    const nestedTestClass = await generator.renderClass(nestedTestModel, inputModel);
-
-    expect(testClass.result).toMatchSnapshot(); 
-    expect(nestedTestClass.result).toMatchSnapshot();
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(2);
+    expect(models[0].result).toMatchSnapshot(); 
+    expect(models[1].result).toMatchSnapshot(); 
   });
 });
diff --git a/test/generators/typescript/preset/MarshallingPreset.spec.ts b/test/generators/typescript/preset/MarshallingPreset.spec.ts
index aea117ac..c9f90817 100644
--- a/test/generators/typescript/preset/MarshallingPreset.spec.ts
+++ b/test/generators/typescript/preset/MarshallingPreset.spec.ts
@@ -35,16 +35,11 @@ describe('Marshalling preset', () => {
         }
       ]
     });
-    const inputModel = await generator.process(doc);
-
-    const testModel = inputModel.models['Test'];
-    const nestedTestModel = inputModel.models['NestedTest'];
-
-    const testClass = await generator.renderClass(testModel, inputModel);
-    const nestedTestClass = await generator.renderClass(nestedTestModel, inputModel);
-
-    expect(testClass.result).toMatchSnapshot();
-    expect(nestedTestClass.result).toMatchSnapshot();
+    const models = await generator.generate(doc);
+    expect(models).toHaveLength(3);
+    expect(models[0].result).toMatchSnapshot(); 
+    expect(models[1].result).toMatchSnapshot(); 
+    expect(models[2].result).toMatchSnapshot(); 
   });
 
   test('should provide a two way conversion', async () => {
diff --git a/test/generators/typescript/preset/__snapshots__/DescriptionPreset.spec.ts.snap b/test/generators/typescript/preset/__snapshots__/DescriptionPreset.spec.ts.snap
index 84622153..59f18c20 100644
--- a/test/generators/typescript/preset/__snapshots__/DescriptionPreset.spec.ts.snap
+++ b/test/generators/typescript/preset/__snapshots__/DescriptionPreset.spec.ts.snap
@@ -11,17 +11,22 @@ class Test {
    * @example Example
    */
   private _numberProp?: number;
+  /**
+   * @example Example 1, Example 2
+   */
   private _objectProp?: NestedTest;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     stringProp: string,
     numberProp?: number,
     objectProp?: NestedTest,
+    additionalProperties?: Map<string, any>,
   }) {
     this._stringProp = input.stringProp;
     this._numberProp = input.numberProp;
     this._objectProp = input.objectProp;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get stringProp(): string { return this._stringProp; }
@@ -33,8 +38,8 @@ class Test {
   get objectProp(): NestedTest | undefined { return this._objectProp; }
   set objectProp(objectProp: NestedTest | undefined) { this._objectProp = objectProp; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }"
 `;
 
@@ -44,18 +49,20 @@ exports[`Description generation should render example function for model 2`] = `
  */
 class NestedTest {
   private _stringProp?: string;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     stringProp?: string,
+    additionalProperties?: Map<string, any>,
   }) {
     this._stringProp = input.stringProp;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get stringProp(): string | undefined { return this._stringProp; }
   set stringProp(stringProp: string | undefined) { this._stringProp = stringProp; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 }"
 `;
diff --git a/test/generators/typescript/preset/__snapshots__/ExamplePreset.spec.ts.snap b/test/generators/typescript/preset/__snapshots__/ExamplePreset.spec.ts.snap
index 72bb598d..df3f94b4 100644
--- a/test/generators/typescript/preset/__snapshots__/ExamplePreset.spec.ts.snap
+++ b/test/generators/typescript/preset/__snapshots__/ExamplePreset.spec.ts.snap
@@ -5,17 +5,18 @@ exports[`Example function generation should render example function for model 1`
   private _stringProp: string;
   private _numberProp?: number;
   private _objectProp?: NestedTest;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
-  private _sTestPatternProperties?: Map<String, string>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     stringProp: string,
     numberProp?: number,
     objectProp?: NestedTest,
+    additionalProperties?: Map<string, any>,
   }) {
     this._stringProp = input.stringProp;
     this._numberProp = input.numberProp;
     this._objectProp = input.objectProp;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get stringProp(): string { return this._stringProp; }
@@ -27,16 +28,13 @@ exports[`Example function generation should render example function for model 1`
   get objectProp(): NestedTest | undefined { return this._objectProp; }
   set objectProp(objectProp: NestedTest | undefined) { this._objectProp = objectProp; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
-
-  get sTestPatternProperties(): Map<String, string> | undefined { return this._sTestPatternProperties; }
-  set sTestPatternProperties(sTestPatternProperties: Map<String, string> | undefined) { this._sTestPatternProperties = sTestPatternProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 
   public static example(): Test {
     const instance = new Test({} as any);
     instance.stringProp = \\"string\\";
-    instance.numberProp = 0;
+    instance.numberProp = 0.0;
     instance.objectProp = NestedTest.example();
     return instance;
   }
@@ -46,19 +44,21 @@ exports[`Example function generation should render example function for model 1`
 exports[`Example function generation should render example function for model 2`] = `
 "class NestedTest {
   private _stringProp?: string;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null>;
+  private _additionalProperties?: Map<string, any>;
 
   constructor(input: {
     stringProp?: string,
+    additionalProperties?: Map<string, any>,
   }) {
     this._stringProp = input.stringProp;
+    this._additionalProperties = input.additionalProperties;
   }
 
   get stringProp(): string | undefined { return this._stringProp; }
   set stringProp(stringProp: string | undefined) { this._stringProp = stringProp; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null> | undefined) { this._additionalProperties = additionalProperties; }
+  get additionalProperties(): Map<string, any> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<string, any> | undefined) { this._additionalProperties = additionalProperties; }
 
   public static example(): NestedTest {
     const instance = new NestedTest({} as any);
diff --git a/test/generators/typescript/preset/utils/ExampleFunctions.spec.ts b/test/generators/typescript/preset/utils/ExampleFunctions.spec.ts
index 3c74cb75..b26575c9 100644
--- a/test/generators/typescript/preset/utils/ExampleFunctions.spec.ts
+++ b/test/generators/typescript/preset/utils/ExampleFunctions.spec.ts
@@ -1,82 +1,72 @@
-import { TypeScriptGenerator } from '../../../../../src/generators';
 import { renderValueFromModel } from '../../../../../src/generators/typescript/presets/utils/ExampleFunction';
-import { TypeScriptRenderer } from '../../../../../src/generators/typescript/TypeScriptRenderer';
-import { CommonInputModel, CommonModel } from '../../../../../src/models';
-class MockTypeScriptRenderer extends TypeScriptRenderer {
+import { CommonModel, ConstrainedAnyModel, ConstrainedArrayModel, ConstrainedBooleanModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedTupleValueModel, ConstrainedUnionModel } from '../../../../../src/models';
 
-}
-const renderer = new MockTypeScriptRenderer(TypeScriptGenerator.defaultOptions, new TypeScriptGenerator(), [], new CommonModel(), new CommonInputModel());
 describe('Marshalling preset', () => {
   describe('.renderValueFromModel()', () => {
-    describe('enums', () => {
-      test('Should render strings correctly', () => {
-        const input = CommonModel.toCommonModel({enum: ['somevalue']});
-        const output = renderValueFromModel(input, renderer);
-        expect(output).toEqual('"somevalue"');
-      });
-      test('Should render numbers correctly', () => {
-        const input = CommonModel.toCommonModel({enum: [1]});
-        const output = renderValueFromModel(input, renderer);
-        expect(output).toEqual('1');
-      });
-      test('Should ignore multiple values', () => {
-        const input = CommonModel.toCommonModel({enum: [1, 'somevalue']});
-        const output = renderValueFromModel(input, renderer);
-        expect(output).toEqual('1');
-      });
-      test('Should use first value if there is more then one', () => {
-        const input = CommonModel.toCommonModel({enum: []});
-        const output = renderValueFromModel(input, renderer);
-        expect(output).toBeUndefined();
-      });
-    });
     test('should render refs correctly', () => {
-      const input = CommonModel.toCommonModel({$ref: 'SomeOtherModel'});
-      const output = renderValueFromModel(input, renderer);
+      const refModel = new ConstrainedAnyModel('test', undefined, '');
+      const model = new ConstrainedReferenceModel('SomeOtherModel', undefined, '', refModel);
+      const output = renderValueFromModel(model);
       expect(output).toEqual('SomeOtherModel.example()');
     });
-    describe('types', () => {
-      test('Should render strings correctly', () => {
-        const input = CommonModel.toCommonModel({type: 'string'});
-        const output = renderValueFromModel(input, renderer);
-        expect(output).toEqual('"string"');
-      });
-      test('Should render numbers correctly', () => {
-        const input = CommonModel.toCommonModel({type: 'number'});
-        const output = renderValueFromModel(input, renderer);
-        expect(output).toEqual('0');
-      });
-      test('Should render booleans correctly', () => {
-        const input = CommonModel.toCommonModel({type: 'boolean'});
-        const output = renderValueFromModel(input, renderer);
-        expect(output).toEqual('true');
-      });
-      test('Should use first value if there is more then one', () => {
-        const input = CommonModel.toCommonModel({type: ['boolean', 'string']});
-        const output = renderValueFromModel(input, renderer);
-        expect(output).toEqual('true');
+    test('Should render strings correctly', () => {
+      const model = new ConstrainedStringModel('test', undefined, '');
+      const output = renderValueFromModel(model);
+      expect(output).toEqual('"string"');
+    });
+    test('Should render numbers correctly', () => {
+      const model = new ConstrainedIntegerModel('test', undefined, '');
+      const output = renderValueFromModel(model);
+      expect(output).toEqual('0');
+    });
+    test('Should render floating numbers correctly', () => {
+      const model = new ConstrainedFloatModel('test', undefined, '');
+      const output = renderValueFromModel(model);
+      expect(output).toEqual('0.0');
+    });
+    test('Should render booleans correctly', () => {
+      const model = new ConstrainedBooleanModel('test', undefined, '');
+      const output = renderValueFromModel(model);
+      expect(output).toEqual('true');
+    });
+    test('Should use first value if there is more then one', () => {
+      const unionModel = new ConstrainedBooleanModel('test', undefined, '');
+      const model = new ConstrainedUnionModel('test', undefined, '', [unionModel]);
+      const output = renderValueFromModel(model);
+      expect(output).toEqual('true');
+    });
+    test('Should render array value', () => {
+      const arrayModel = new ConstrainedBooleanModel('test', undefined, '');
+      const model = new ConstrainedArrayModel('test', undefined, '', arrayModel);
+      const output = renderValueFromModel(model);
+      expect(output).toEqual('[true]');
+    });
+    test('Should handle unknown types', () => {
+      const model = new ConstrainedAnyModel('test', undefined, '');
+      const output = renderValueFromModel(model);
+      expect(output).toEqual(undefined);
+    });
+    describe('tuples', () => {
+      test('should not render anything if no items are defined', () => {
+        const model = new ConstrainedTupleModel('test', undefined, '', []);
+        const output = renderValueFromModel(model);
+        expect(output).toEqual(undefined);
       });
-      describe('array', () => {
-        test('should not render anything if no items are defined', () => {
-          const input = CommonModel.toCommonModel({type: 'array'});
-          const output = renderValueFromModel(input, renderer);
-          expect(output).toEqual('[]');
-        });
-        test('should render multiple array values', () => {
-          const input = CommonModel.toCommonModel({type: 'array', items: [{type: 'string'}, {type: 'number'}]});
-          const output = renderValueFromModel(input, renderer);
-          expect(output).toEqual('["string", 0]');
-        });
-        test('should render single array value', () => {
-          const input = CommonModel.toCommonModel({type: 'array', items: {type: 'string'}});
-          const output = renderValueFromModel(input, renderer);
-          expect(output).toEqual('["string"]');
-        });
+      test('should render multiple array values', () => {
+        const stringModel = new ConstrainedStringModel('test', undefined, 'String');
+        const tupleValueModel1 = new ConstrainedTupleValueModel(0, stringModel);
+        const integerModel = new ConstrainedIntegerModel('test', undefined, '');
+        const tupleValueModel2 = new ConstrainedTupleValueModel(0, integerModel);
+        const model = new ConstrainedTupleModel('test', undefined, '', [tupleValueModel1, tupleValueModel2]);
+        const output = renderValueFromModel(model);
+        expect(output).toEqual('["string",0]');
       });
-      test('Should ignore if none are present', () => {
-        const input = CommonModel.toCommonModel({type: []});
-        const output = renderValueFromModel(input, renderer);
-        expect(output).toBeUndefined();
+      test('should render single array value', () => {
+        const stringModel = new ConstrainedStringModel('test', undefined, 'String');
+        const tupleValueModel = new ConstrainedTupleValueModel(0, stringModel);
+        const model = new ConstrainedTupleModel('test', undefined, '', [tupleValueModel]);
+        const output = renderValueFromModel(model);
+        expect(output).toEqual('["string"]');
       });
     });
   });
diff --git a/test/generators/typescript/renderers/EnumRenderer.spec.ts b/test/generators/typescript/renderers/EnumRenderer.spec.ts
deleted file mode 100644
index e305031f..00000000
--- a/test/generators/typescript/renderers/EnumRenderer.spec.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { TypeScriptGenerator } from '../../../../src/generators';
-import { EnumRenderer } from '../../../../src/generators/typescript/renderers/EnumRenderer';
-import { CommonInputModel, CommonModel } from '../../../../src/models';
-
-describe('EnumRenderer', () => {
-  let renderer: EnumRenderer;
-  beforeEach(() => {
-    renderer = new EnumRenderer(TypeScriptGenerator.defaultOptions, new TypeScriptGenerator(), [], new CommonModel(), new CommonInputModel());
-  });
-
-  describe('normalizeKey()', () => {
-    test('should correctly format " " to correct key', () => {
-      const key = renderer.normalizeKey('something something');
-      expect(key).toEqual('SOMETHING_SOMETHING');
-    });
-    test('should correctly format "_" to correct key', () => {
-      const key = renderer.normalizeKey('something_something');
-      expect(key).toEqual('SOMETHING_SOMETHING');
-    });
-  });
-});
diff --git a/test/helpers/CommonModelToMetaModel.spec.ts b/test/helpers/CommonModelToMetaModel.spec.ts
index f3e22fbb..ec6a681f 100644
--- a/test/helpers/CommonModelToMetaModel.spec.ts
+++ b/test/helpers/CommonModelToMetaModel.spec.ts
@@ -14,18 +14,43 @@ describe('CommonModelToMetaModel', () => {
     expect(model).not.toBeUndefined();
     expect(model instanceof AnyModel).toEqual(true);
   });
-  test('should convert to enum model', () => { 
-    const cm = new CommonModel();
-    cm.type = 'string';
-    cm.$id = 'test';
-    cm.enum = [
-      'test'
-    ];
-
-    const model = convertToMetaModel(cm);
-
-    expect(model).not.toBeUndefined();
-    expect(model instanceof EnumModel).toEqual(true);
+  describe('should convert to enum model', () => {
+    test('when string enums', () => { 
+      const cm = new CommonModel();
+      cm.type = 'string';
+      cm.$id = 'test';
+      cm.enum = [
+        'test'
+      ];
+  
+      const model = convertToMetaModel(cm);
+  
+      expect(model).not.toBeUndefined();
+      expect(model instanceof EnumModel).toEqual(true);
+      expect((model as EnumModel).values.length).toEqual(1);
+      expect((model as EnumModel).values[0].key).toEqual('test');
+    });
+    test('when different types of values', () => { 
+      const cm = new CommonModel();
+      cm.type = ['string', 'object', 'number', 'boolean'];
+      cm.$id = 'test';
+      cm.enum = [
+        {test: 1},
+        123,
+        'test',
+        true
+      ];
+  
+      const model = convertToMetaModel(cm);
+  
+      expect(model).not.toBeUndefined();
+      expect(model instanceof EnumModel).toEqual(true);
+      expect((model as EnumModel).values.length).toEqual(4);
+      expect((model as EnumModel).values[0].value).toEqual({test: 1});
+      expect((model as EnumModel).values[1].value).toEqual(123);
+      expect((model as EnumModel).values[2].value).toEqual('test');
+      expect((model as EnumModel).values[3].value).toEqual(true);
+    });
   });
   test('should convert to string model', () => { 
     const cm = new CommonModel();
diff --git a/test/helpers/ConstrainHelpers.spec.ts b/test/helpers/ConstrainHelpers.spec.ts
index 35fc8c8d..13450f9b 100644
--- a/test/helpers/ConstrainHelpers.spec.ts
+++ b/test/helpers/ConstrainHelpers.spec.ts
@@ -164,9 +164,11 @@ describe('ConstrainHelpers', () => {
         constrainedName: ''
       });
       expect(constrainedModel instanceof ConstrainedEnumModel).toEqual(true);
-      expect((constrainedModel as ConstrainedEnumModel).values[0] instanceof ConstrainedEnumValueModel).toEqual(true);
+      const enumModel = constrainedModel as ConstrainedEnumModel;
       expect(mockedConstraints.modelName).toHaveBeenCalledTimes(1);
       expect(mockedTypeMapping.Enum).toHaveBeenCalledTimes(1);
+      expect(enumModel.values[0].key).toEqual('test');
+      expect(enumModel.values[0].value).toEqual(123);
     });
   });
   describe('constrain DictionaryModel', () => {