Repository: asyncapi/modelina
Pull request #736 (2022-04-27 03:00:27)

refactor: convert TS to new constraint setup 
**Description**
This PR converts the TS generator to the new constraint setup introduced in https://github.com/asyncapi/modelina/pull/725

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=736)

[![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=736&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=736&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=736&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=736&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=736&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=736&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=736&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=736&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=736&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=736&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=736&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=736&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=736) 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=736&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=736)

[![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=736&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=736&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=736&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=736&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=736&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=736&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=736&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=736&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=736&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=736&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=736&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=736&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=736) 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=736&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=736)

[![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=736&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=736&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=736&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=736&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=736&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=736&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=736&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=736&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=736&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=736&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=736&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=736&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=736) 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=736&metric=duplicated_lines_density&view=list) No Duplication information


Samridhi-98: /rtm

Patch:
diff --git a/src/generators/typescript/TypeScriptConstrainer.ts b/src/generators/typescript/TypeScriptConstrainer.ts
index c07e7fff..bb473d2f 100644
--- a/src/generators/typescript/TypeScriptConstrainer.ts
+++ b/src/generators/typescript/TypeScriptConstrainer.ts
@@ -1,231 +1,68 @@
-import { ConstrainedAnyModel, ConstrainedBooleanModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedMetaModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedTupleValueModel, ConstrainedArrayModel, ConstrainedUnionModel, ConstrainedEnumModel, ConstrainedDictionaryModel, ConstrainedEnumValueModel } from '../../models/ConstrainedMetaModel';
-import { AnyModel, BooleanModel, FloatModel, IntegerModel, MetaModel, ObjectModel, ReferenceModel, StringModel, TupleModel, ArrayModel, UnionModel, EnumModel, DictionaryModel } from '../../models/MetaModel';
-import { defaultPropertyKeyConstraints, PropertyKeyConstraintType } from './constrainer/PropertyKeyConstrainer';
-import { defaultModelNameConstraints, ModelNameConstraintType } from './constrainer/ModelNameConstrainer';
-import { defaultEnumKeyConstraints, EnumConstraintType } from './constrainer/EnumConstrainer';
+import { ConstrainedUnionModel } from '../../models';
 import { Logger } from '../../utils';
+import { TypeMapping } from '../../helpers';
+import { defaultEnumKeyConstraints, defaultEnumValueConstraints } from './constrainer/EnumConstrainer';
+import { defaultModelNameConstraints } from './constrainer/ModelNameConstrainer';
+import { defaultPropertyKeyConstraints } from './constrainer/PropertyKeyConstrainer';
+import { TypeScriptRenderer } from './TypeScriptRenderer';
 
-export interface TypeScriptConstraints {
-  enumKey: EnumConstraintType,
-  modelName: ModelNameConstraintType,
-  propertyKey: PropertyKeyConstraintType,
-}
-
-export const DefaultTypeScriptConstraints: TypeScriptConstraints = {
-  enumKey: defaultEnumKeyConstraints(),
-  modelName: defaultModelNameConstraints(),
-  propertyKey: defaultPropertyKeyConstraints()
-};
-
-type TypeMappingFunction<T extends ConstrainedMetaModel> = (model: T) => string;
-
-type TypeMapping = {
-  Object?: TypeMappingFunction<ConstrainedObjectModel>,
-  Reference?: TypeMappingFunction<ConstrainedReferenceModel>,
-  Any?: TypeMappingFunction<ConstrainedAnyModel>,
-  Float?: TypeMappingFunction<ConstrainedFloatModel>,
-  Integer?: TypeMappingFunction<ConstrainedIntegerModel>,
-  String?: TypeMappingFunction<ConstrainedStringModel>,
-  Boolean?: TypeMappingFunction<ConstrainedBooleanModel>,
-  Tuple?: TypeMappingFunction<ConstrainedTupleModel>,
-  Array?: TypeMappingFunction<ConstrainedArrayModel>,
-  Enum?: TypeMappingFunction<ConstrainedEnumModel>,
-  Union?: TypeMappingFunction<ConstrainedUnionModel>,
-  Dictionary?: TypeMappingFunction<ConstrainedDictionaryModel>
-}
-
-function constrainReferenceModel(constrainedName: string, metaModel: ReferenceModel, typeMapping: TypeMapping, constrainRules: TypeScriptConstraints): ConstrainedReferenceModel {
-  const constrainedRefModel = constrainMetaModel(metaModel.ref, typeMapping, constrainRules);
-  const constrainedModel = new ConstrainedReferenceModel(constrainedName, metaModel.originalInput, '', constrainedRefModel);
-  if (typeMapping.Reference !== undefined) {
-    constrainedModel.type = typeMapping.Reference(constrainedModel);
-  } else {
-    constrainedModel.type = constrainedModel.name;
-  }
-  return constrainedModel;
-}
-function constrainAnyModel(constrainedName: string, metaModel: AnyModel, typeMapping: TypeMapping): ConstrainedAnyModel {
-  const constrainedModel = new ConstrainedAnyModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.Any !== undefined) {
-    constrainedModel.type = typeMapping.Any(constrainedModel);
-  } else {
-    constrainedModel.type = 'any';
-  }
-  return constrainedModel; 
-}
-function constrainFloatModel(constrainedName: string, metaModel: FloatModel, typeMapping: TypeMapping): ConstrainedFloatModel {
-  const constrainedModel = new ConstrainedFloatModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.Float !== undefined) {
-    constrainedModel.type = typeMapping.Float(constrainedModel);
-  } else {
-    constrainedModel.type = 'number';
-  }
-  return constrainedModel;
-}
-function constrainIntegerModel(constrainedName: string, metaModel: IntegerModel, typeMapping: TypeMapping): ConstrainedIntegerModel {
-  const constrainedModel = new ConstrainedIntegerModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.Integer !== undefined) {
-    constrainedModel.type = typeMapping.Integer(constrainedModel);
-  } else {
-    constrainedModel.type = 'integer';
-  }
-  return constrainedModel;
-}
-function constrainStringModel(constrainedName: string, metaModel: IntegerModel, typeMapping: TypeMapping): ConstrainedIntegerModel {
-  const constrainedModel = new ConstrainedStringModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.String !== undefined) {
-    constrainedModel.type = typeMapping.String(constrainedModel);
-  } else {
-    constrainedModel.type = 'string';
-  }
-  return constrainedModel;
-}
-function constrainBooleanModel(constrainedName: string, metaModel: BooleanModel, typeMapping: TypeMapping): ConstrainedBooleanModel {
-  const constrainedModel = new ConstrainedBooleanModel(constrainedName, metaModel.originalInput, '');
-  if (typeMapping.Boolean !== undefined) {
-    constrainedModel.type = typeMapping.Boolean(constrainedModel);
-  } else {
-    constrainedModel.type = 'boolean';
-  }
-  return constrainedModel;
-}
-function constrainTupleModel(constrainedName: string, metaModel: TupleModel, typeMapping: TypeMapping, constrainRules: TypeScriptConstraints): ConstrainedTupleModel {
-  const constrainedTupleModels = metaModel.tuple.map((tupleValue) => {
-    const tupleType = constrainMetaModel(tupleValue.value, typeMapping, constrainRules);
-    return new ConstrainedTupleValueModel(tupleValue.index, tupleType);
-  });
-  const constrainedModel = new ConstrainedTupleModel(constrainedName, metaModel.originalInput, '', constrainedTupleModels);
-  if (typeMapping.Tuple !== undefined) {
-    constrainedModel.type = typeMapping.Tuple(constrainedModel);
-  } else {
-    const tupleTypes = constrainedTupleModels.map((constrainedType) => {
+export const TypeScriptDefaultTypeMapping: TypeMapping<TypeScriptRenderer> = {
+  Object ({constrainedModel}): string {
+    return constrainedModel.name;
+  },
+  Reference ({constrainedModel}): string {
+    return constrainedModel.name;
+  },
+  Any (): string {
+    return 'any';
+  },
+  Float (): string {
+    return 'number';
+  },
+  Integer (): string {
+    return 'integer'; 
+  },
+  String (): string {
+    return 'string';
+  },
+  Boolean (): string {
+    return 'boolean';
+  },
+  Tuple ({constrainedModel}): string {
+    const tupleTypes = constrainedModel.tuple.map((constrainedType) => {
       return constrainedType.value.type;
     });
-    const tupleType = `[${tupleTypes.join(', ')}]`;
-    constrainedModel.type = tupleType;
-  }
-  return constrainedModel;
-}
-function constrainArrayModel(constrainedName: string, metaModel: ArrayModel, typeMapping: TypeMapping, constrainRules: TypeScriptConstraints): ConstrainedArrayModel {
-  const constrainedValueModel = constrainMetaModel(metaModel.valueModel, typeMapping, constrainRules);
-  const constrainedModel = new ConstrainedArrayModel(constrainedName, metaModel.originalInput, '', constrainedValueModel);
-  if (typeMapping.Array !== undefined) {
-    constrainedModel.type = typeMapping.Array(constrainedModel);
-  } else {
-    constrainedModel.type = `${constrainedValueModel.type}[]`;
-  }
-  return constrainedModel;
-}
-function constrainUnionModel(constrainedName: string, metaModel: UnionModel, typeMapping: TypeMapping, constrainRules: TypeScriptConstraints): ConstrainedUnionModel {
-  const constrainedUnionModels = metaModel.union.map((unionValue) => {
-    return constrainMetaModel(unionValue, typeMapping, constrainRules);
-  });
-  const constrainedModel = new ConstrainedUnionModel(constrainedName, metaModel.originalInput, '', constrainedUnionModels);
-  if (typeMapping.Union !== undefined) {
-    constrainedModel.type = typeMapping.Union(constrainedModel);
-  } else {
-    constrainedModel.type = constrainedUnionModels.join(' | ');
-  }
-  return constrainedModel;
-}
-function constrainDictionaryModel(constrainedName: string, metaModel: DictionaryModel, typeMapping: TypeMapping, constrainRules: TypeScriptConstraints): ConstrainedDictionaryModel {
-  let keyModel;    
-  //There is some restrictions on what can be used as keys for dictionaries.
-  if (metaModel.key instanceof UnionModel) {
-    Logger.error('Key for dictionary is not allowed to be union type, falling back to any model.');
-    const anyModel = new AnyModel(metaModel.key.name, metaModel.key.originalInput);
-    keyModel = constrainMetaModel(anyModel, typeMapping, constrainRules);
-  } else {
-    keyModel = constrainMetaModel(metaModel.key, typeMapping, constrainRules);
-  }
-  const valueModel = constrainMetaModel(metaModel.value, typeMapping, constrainRules);
-  const constrainedModel = new ConstrainedDictionaryModel(constrainedName, metaModel.originalInput, '', keyModel, valueModel, metaModel.serializationType);
-  if (typeMapping.Dictionary !== undefined) {
-    constrainedModel.type = typeMapping.Dictionary(constrainedModel);
-  } else {
-    const type = `{ [name: ${keyModel.type}]: ${valueModel.type} }`;
-    constrainedModel.type = type;
-  }
-  return constrainedModel;
-}
-
-function constrainObjectModel(constrainedName: string, objectModel: ObjectModel, typeMapping: TypeMapping, constrainRules: TypeScriptConstraints): ConstrainedObjectModel {
-  const constrainedObjectModel = new ConstrainedObjectModel(constrainedName, objectModel.originalInput, '', {});
-  for (const [propertyKey, propertyMetaModel] of Object.entries(objectModel.properties)) {
-    const constrainedPropertyName = constrainRules.propertyKey({propertyKey, constrainedObjectModel, objectModel});
-    const constrainedProperty = constrainMetaModel(propertyMetaModel, typeMapping, constrainRules);
-    constrainedObjectModel.properties[String(constrainedPropertyName)] = constrainedProperty;
-  }
-  if (typeMapping.Object !== undefined) {
-    constrainedObjectModel.type = typeMapping.Object(constrainedObjectModel);
-  } else {
-    constrainedObjectModel.type = constrainedName;
-  }
-  return constrainedObjectModel;
-}
-
-export function ConstrainEnumModel(constrainedName: string, enumModel: EnumModel, typeMapping: TypeMapping, constrainRules: TypeScriptConstraints): ConstrainedEnumModel {
-  const constrainedModel = new ConstrainedEnumModel(constrainedName, enumModel.originalInput, '', []);
-
-  for (const enumValue of enumModel.values) {
-    const constrainedEnumKey = constrainRules.enumKey({enumKey: String(enumValue.key), enumModel, constrainedEnumModel: constrainedModel});
-    let normalizedEnumValue;
-    switch (typeof enumValue.value) {
-    case 'string':
-    case 'boolean':
-      normalizedEnumValue = `"${enumValue.value}"`;
-      break;
-    case 'bigint':
-    case 'number': {
-      normalizedEnumValue = enumValue.value;
-      break;
-    }
-    case 'object': {
-      normalizedEnumValue = `'${JSON.stringify(enumValue.value)}'`;
-      break;
-    }
-    default: {
-      normalizedEnumValue = String(enumValue.value);
-    }
+    return `[${tupleTypes.join(', ')}]`;
+  },
+  Array ({constrainedModel}): string {
+    return `${constrainedModel.valueModel.type}[]`;
+  },
+  Enum ({constrainedModel}): string {
+    return constrainedModel.name;
+  },
+  Union ({constrainedModel}): string {
+    const unionTypes = constrainedModel.union.map((unionModel) => {
+      return unionModel.type;
+    });
+    return unionTypes.join(' | ');
+  },
+  Dictionary ({constrainedModel}): string {
+    let keyType;    
+    //There is some restrictions on what can be used as keys for dictionaries.
+    if (constrainedModel.key instanceof ConstrainedUnionModel) {
+      Logger.error('Key for dictionary is not allowed to be union type, falling back to any model.');
+      keyType = 'any';
+    } else {
+      keyType = constrainedModel.key.type;
     }
-    const constrainedEnumValueModel = new ConstrainedEnumValueModel(constrainedEnumKey, normalizedEnumValue);
-    constrainedModel.values.push(constrainedEnumValueModel);
-  }
-  if (typeMapping.Enum !== undefined) {
-    constrainedModel.type = typeMapping.Enum(constrainedModel);
-  } else {
-    constrainedModel.type = constrainedName;
-  }
-  return constrainedModel;
-}
 
-export function constrainMetaModel(metaModel: MetaModel, typeMapping: TypeMapping, constrainRules: TypeScriptConstraints): ConstrainedMetaModel {
-  const constrainedName = constrainRules.modelName({modelName: metaModel.name});
-  
-  if (metaModel instanceof ObjectModel) {
-    return constrainObjectModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof ReferenceModel) {
-    return constrainReferenceModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof AnyModel) {
-    return constrainAnyModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof FloatModel) {
-    return constrainFloatModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof IntegerModel) {
-    return constrainIntegerModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof StringModel) {
-    return constrainStringModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof BooleanModel) {
-    return constrainBooleanModel(constrainedName, metaModel, typeMapping);
-  } else if (metaModel instanceof TupleModel) {
-    return constrainTupleModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof ArrayModel) {
-    return constrainArrayModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof UnionModel) {
-    return constrainUnionModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof EnumModel) {
-    return ConstrainEnumModel(constrainedName, metaModel, typeMapping, constrainRules);
-  } else if (metaModel instanceof DictionaryModel) {
-    return constrainDictionaryModel(constrainedName, metaModel, typeMapping, constrainRules);
+    return `{ [name: ${keyType}]: ${constrainedModel.value.type} }`;
   }
-  throw new Error('Could not constrain model');
-}
+};
+
+export const TypeScriptDefaultConstraints = {
+  enumKey: defaultEnumKeyConstraints(),
+  enumValue: defaultEnumValueConstraints(),
+  modelName: defaultModelNameConstraints(),
+  propertyKey: defaultPropertyKeyConstraints()
+};
diff --git a/src/generators/typescript/TypeScriptGenerator.ts b/src/generators/typescript/TypeScriptGenerator.ts
index 6a74b1e8..93d203f8 100644
--- a/src/generators/typescript/TypeScriptGenerator.ts
+++ b/src/generators/typescript/TypeScriptGenerator.ts
@@ -5,19 +5,23 @@ import {
   defaultGeneratorOptions
 } from '../AbstractGenerator';
 import { CommonModel, CommonInputModel, RenderOutput } from '../../models';
-import { TypeHelpers, ModelKind, CommonNamingConvention, CommonNamingConventionImplementation } from '../../helpers';
+import { TypeHelpers, ModelKind, CommonNamingConvention, CommonNamingConventionImplementation, TypeMapping, Constraints } from '../../helpers';
 import { TS_EXPORT_KEYWORD_PRESET } from './presets';
 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 { TypeScriptRenderer } from './TypeScriptRenderer';
+import { TypeScriptDefaultConstraints, TypeScriptDefaultTypeMapping } from './TypeScriptConstrainer';
 
 export interface TypeScriptOptions extends CommonGeneratorOptions<TypeScriptPreset> {
   renderTypes?: boolean;
   modelType?: 'class' | 'interface';
   enumType?: 'enum' | 'union';
   namingConvention?: CommonNamingConvention;
+  typeMapping: TypeMapping<TypeScriptRenderer>;
+  constraints: Constraints
 }
 export interface TypeScriptRenderCompleteModelOptions {
   moduleSystem?: 'ESM' | 'CJS';
@@ -34,13 +38,17 @@ export class TypeScriptGenerator extends AbstractGenerator<TypeScriptOptions,Typ
     modelType: 'class',
     enumType: 'enum',
     defaultPreset: TS_DEFAULT_PRESET,
-    namingConvention: CommonNamingConventionImplementation
+    namingConvention: CommonNamingConventionImplementation,
+    typeMapping: TypeScriptDefaultTypeMapping,
+    constraints: TypeScriptDefaultConstraints
   };
 
   constructor(
-    options: TypeScriptOptions = TypeScriptGenerator.defaultOptions,
+    options: Partial<TypeScriptOptions> = TypeScriptGenerator.defaultOptions,
   ) {
-    super('TypeScript', TypeScriptGenerator.defaultOptions, options);
+    const mergedOptions = {...TypeScriptGenerator.defaultOptions, ...options};
+
+    super('TypeScript', TypeScriptGenerator.defaultOptions, mergedOptions);
   }
 
   /**
diff --git a/src/generators/typescript/constrainer/EnumConstrainer.ts b/src/generators/typescript/constrainer/EnumConstrainer.ts
index a9092495..3452d5b2 100644
--- a/src/generators/typescript/constrainer/EnumConstrainer.ts
+++ b/src/generators/typescript/constrainer/EnumConstrainer.ts
@@ -1,7 +1,6 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import { ConstrainedEnumModel, EnumModel } from '../../../models';
 import { NO_NUMBER_START_CHAR, NO_DUPLICATE_ENUM_KEYS, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS} from '../../../helpers/Constraints';
-import { FormatHelpers } from '../../../helpers';
+import { EnumKeyConstraint, EnumValueConstraint, FormatHelpers } from '../../../helpers';
 import { isReservedTypeScriptKeyword } from '../Constants';
 
 export type ModelEnumKeyConstraints = {
@@ -27,40 +26,42 @@ export const DefaultEnumKeyConstraints: ModelEnumKeyConstraints = {
   }
 };
 
-export type EnumKeyContext = {
-  enumKey: string,
-  constrainedEnumModel: ConstrainedEnumModel,
-  enumModel: EnumModel
+export function defaultEnumKeyConstraints(customConstraints?: Partial<ModelEnumKeyConstraints>): EnumKeyConstraint {
+  const constraints = {...DefaultEnumKeyConstraints, ...customConstraints};
+
+  return ({enumKey, enumModel, constrainedEnumModel}) => {
+    let constrainedEnumKey = enumKey;
+    constrainedEnumKey = constraints.NO_SPECIAL_CHAR(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_NUMBER_START_CHAR(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_EMPTY_VALUE(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_RESERVED_KEYWORDS(constrainedEnumKey);
+    constrainedEnumKey = constraints.NAMING_FORMATTER(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_DUPLICATE_KEYS(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER);
+    return constrainedEnumKey;
+  };
 }
-export type EnumConstraintType = (context: EnumKeyContext, constraints?: ModelEnumKeyConstraints) => string;
 
-export function defaultEnumKeyConstraints(customConstraints?: ModelEnumKeyConstraints): EnumConstraintType {
-  const constraints = DefaultEnumKeyConstraints;
-  if (customConstraints !== undefined) {
-    if (customConstraints.NAMING_FORMATTER !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NAMING_FORMATTER;
+export function defaultEnumValueConstraints(): EnumValueConstraint {
+  return ({enumValue}) => {
+    let normalizedEnumValue;
+    switch (typeof enumValue) {
+    case 'string':
+    case 'boolean':
+      normalizedEnumValue = `"${enumValue}"`;
+      break;
+    case 'bigint':
+    case 'number': {
+      normalizedEnumValue = `${enumValue}`;
+      break;
     }
-    if (customConstraints.NO_SPECIAL_CHAR !== undefined) {
-      constraints.NO_SPECIAL_CHAR = customConstraints.NO_SPECIAL_CHAR;
+    case 'object': {
+      normalizedEnumValue = `'${JSON.stringify(enumValue)}'`;
+      break;
     }
-    if (customConstraints.NO_NUMBER_START_CHAR !== undefined) {
-      constraints.NO_NUMBER_START_CHAR = customConstraints.NO_NUMBER_START_CHAR;
+    default: {
+      normalizedEnumValue = String(enumValue);
     }
-    if (customConstraints.NO_RESERVED_KEYWORDS !== undefined) {
-      constraints.NO_RESERVED_KEYWORDS = customConstraints.NO_RESERVED_KEYWORDS;
     }
-    if (customConstraints.NO_DUPLICATE_KEYS !== undefined) {
-      constraints.NO_DUPLICATE_KEYS = customConstraints.NO_DUPLICATE_KEYS;
-    }
-  }
-  return ({enumKey, enumModel, constrainedEnumModel}) => {
-    let constrainedEnumKey = enumKey;
-    constrainedEnumKey = constraints.NO_SPECIAL_CHAR!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_NUMBER_START_CHAR!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_EMPTY_VALUE!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_RESERVED_KEYWORDS!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NAMING_FORMATTER!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_DUPLICATE_KEYS!(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER!);
-    return constrainedEnumKey;
+    return normalizedEnumValue;
   };
 }
diff --git a/src/generators/typescript/constrainer/ModelNameConstrainer.ts b/src/generators/typescript/constrainer/ModelNameConstrainer.ts
index 8839eeb6..61344485 100644
--- a/src/generators/typescript/constrainer/ModelNameConstrainer.ts
+++ b/src/generators/typescript/constrainer/ModelNameConstrainer.ts
@@ -1,14 +1,13 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import { NO_NUMBER_START_CHAR, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS} from '../../../helpers/Constraints';
-import { FormatHelpers } from '../../../helpers';
+import { FormatHelpers, ModelNameConstraint } from '../../../helpers';
 import { isReservedTypeScriptKeyword } from '../Constants';
 
 export type ModelNameConstraints = {
-  NO_SPECIAL_CHAR?: (value: string) => string;
-  NO_NUMBER_START_CHAR?: (value: string) => string;
-  NO_EMPTY_VALUE?: (value: string) => string;
-  NAMING_FORMATTER?: (value: string) => string;
-  NO_RESERVED_KEYWORDS?: (value: string) => string;
+  NO_SPECIAL_CHAR: (value: string) => string;
+  NO_NUMBER_START_CHAR: (value: string) => string;
+  NO_EMPTY_VALUE: (value: string) => string;
+  NAMING_FORMATTER: (value: string) => string;
+  NO_RESERVED_KEYWORDS: (value: string) => string;
 };
 
 export const DefaultModelNameConstraints: ModelNameConstraints = {
@@ -26,38 +25,16 @@ export const DefaultModelNameConstraints: ModelNameConstraints = {
     return NO_RESERVED_KEYWORDS(value, isReservedTypeScriptKeyword); 
   }
 };
-export type ModelNameContext = {
-  modelName: string
-}
-export type ModelNameConstraintType = (context: ModelNameContext) => string;
-
-export function defaultModelNameConstraints(customConstraints?: ModelNameConstraints): ModelNameConstraintType {
-  const constraints = DefaultModelNameConstraints;
-  if (customConstraints !== undefined) {
-    if (customConstraints.NO_SPECIAL_CHAR !== undefined) {
-      constraints.NO_SPECIAL_CHAR = customConstraints.NO_SPECIAL_CHAR;
-    }
-    if (customConstraints.NO_NUMBER_START_CHAR !== undefined) {
-      constraints.NO_NUMBER_START_CHAR = customConstraints.NO_NUMBER_START_CHAR;
-    }
-    if (customConstraints.NO_EMPTY_VALUE !== undefined) {
-      constraints.NO_EMPTY_VALUE = customConstraints.NO_EMPTY_VALUE;
-    }
-    if (customConstraints.NAMING_FORMATTER !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NAMING_FORMATTER;
-    }
-    if (customConstraints.NO_RESERVED_KEYWORDS !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NO_RESERVED_KEYWORDS;
-    }
-  }
+export function defaultModelNameConstraints(customConstraints?: Partial<ModelNameConstraints>): ModelNameConstraint {
+  const constraints = {...DefaultModelNameConstraints, ...customConstraints};
 
   return ({modelName}) => {
     let constrainedValue = modelName;
-    constrainedValue = constraints.NO_SPECIAL_CHAR!(constrainedValue);
-    constrainedValue = constraints.NO_NUMBER_START_CHAR!(constrainedValue);
-    constrainedValue = constraints.NO_EMPTY_VALUE!(constrainedValue);
-    constrainedValue = constraints.NAMING_FORMATTER!(constrainedValue);
-    constrainedValue = constraints.NO_RESERVED_KEYWORDS!(constrainedValue);
+    constrainedValue = constraints.NO_SPECIAL_CHAR(constrainedValue);
+    constrainedValue = constraints.NO_NUMBER_START_CHAR(constrainedValue);
+    constrainedValue = constraints.NO_EMPTY_VALUE(constrainedValue);
+    constrainedValue = constraints.NO_RESERVED_KEYWORDS(constrainedValue);
+    constrainedValue = constraints.NAMING_FORMATTER(constrainedValue);
     return constrainedValue;
   };
 }
diff --git a/src/generators/typescript/constrainer/PropertyKeyConstrainer.ts b/src/generators/typescript/constrainer/PropertyKeyConstrainer.ts
index 0d9e136b..4fe673b2 100644
--- a/src/generators/typescript/constrainer/PropertyKeyConstrainer.ts
+++ b/src/generators/typescript/constrainer/PropertyKeyConstrainer.ts
@@ -1,16 +1,15 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import { ConstrainedObjectModel, ObjectModel } from '../../../models';
 import { NO_NUMBER_START_CHAR, NO_DUPLICATE_PROPERTIES, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS} from '../../../helpers/Constraints';
-import { FormatHelpers } from '../../../helpers';
+import { FormatHelpers, PropertyKeyConstraint } from '../../../helpers';
 import { isReservedTypeScriptKeyword } from '../Constants';
 
 export type PropertyKeyConstraintOptions = {
-  NO_SPECIAL_CHAR?: (value: string) => string;
-  NO_NUMBER_START_CHAR?: (value: string) => string;
-  NO_DUPLICATE_PROPERTIES?: (constrainedObjectModel: ConstrainedObjectModel, objectModel: ObjectModel, propertyName: string, namingFormatter: (value: string) => string) => string;
-  NO_EMPTY_VALUE?: (value: string) => string;
-  NAMING_FORMATTER?: (value: string) => string;
-  NO_RESERVED_KEYWORDS?: (value: string) => string;
+  NO_SPECIAL_CHAR: (value: string) => string;
+  NO_NUMBER_START_CHAR: (value: string) => string;
+  NO_DUPLICATE_PROPERTIES: (constrainedObjectModel: ConstrainedObjectModel, objectModel: ObjectModel, propertyName: string, namingFormatter: (value: string) => string) => string;
+  NO_EMPTY_VALUE: (value: string) => string;
+  NAMING_FORMATTER: (value: string) => string;
+  NO_RESERVED_KEYWORDS: (value: string) => string;
 };
 
 export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
@@ -27,46 +26,18 @@ export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
     return NO_RESERVED_KEYWORDS(value, isReservedTypeScriptKeyword); 
   }
 };
+export function defaultPropertyKeyConstraints(customConstraints?: Partial<PropertyKeyConstraintOptions>): PropertyKeyConstraint {
+  const constraints = {...DefaultPropertyKeyConstraints, ...customConstraints};
 
-export type PropertyKeyContext = {
-  propertyKey: string,
-  constrainedObjectModel: ConstrainedObjectModel,
-  objectModel: ObjectModel
-}
-
-export type PropertyKeyConstraintType = (context: PropertyKeyContext) => string;
-
-export function defaultPropertyKeyConstraints(customConstraints?: PropertyKeyConstraintOptions): PropertyKeyConstraintType {
-  const constraints = DefaultPropertyKeyConstraints;
-  if (customConstraints !== undefined) {
-    if (customConstraints.NAMING_FORMATTER !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NAMING_FORMATTER;
-    }
-    if (customConstraints.NO_SPECIAL_CHAR !== undefined) {
-      constraints.NO_SPECIAL_CHAR = customConstraints.NO_SPECIAL_CHAR;
-    }
-    if (customConstraints.NO_NUMBER_START_CHAR !== undefined) {
-      constraints.NO_NUMBER_START_CHAR = customConstraints.NO_NUMBER_START_CHAR;
-    }
-    if (customConstraints.NO_EMPTY_VALUE !== undefined) {
-      constraints.NO_EMPTY_VALUE = customConstraints.NO_EMPTY_VALUE;
-    }
-    if (customConstraints.NO_RESERVED_KEYWORDS !== undefined) {
-      constraints.NO_RESERVED_KEYWORDS = customConstraints.NO_RESERVED_KEYWORDS;
-    }
-    if (customConstraints.NO_DUPLICATE_PROPERTIES !== undefined) {
-      constraints.NO_DUPLICATE_PROPERTIES = customConstraints.NO_DUPLICATE_PROPERTIES;
-    }
-  }
-  return ({propertyKey, constrainedObjectModel, objectModel}: PropertyKeyContext) => {
+  return ({propertyKey, constrainedObjectModel, objectModel}) => {
     let constrainedPropertyKey = propertyKey;
 
-    constrainedPropertyKey = constraints.NO_SPECIAL_CHAR!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_EMPTY_VALUE!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_RESERVED_KEYWORDS!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NAMING_FORMATTER!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES!(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER!);
+    constrainedPropertyKey = constraints.NO_SPECIAL_CHAR(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_EMPTY_VALUE(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_RESERVED_KEYWORDS(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NAMING_FORMATTER(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER);
     return constrainedPropertyKey;
   };
 }


Test patch:
diff --git a/test/TestUtils/TestRenderers.ts b/test/TestUtils/TestRenderers.ts
index 8c6404d4..358e85e3 100644
--- a/test/TestUtils/TestRenderers.ts
+++ b/test/TestUtils/TestRenderers.ts
@@ -2,6 +2,7 @@ import { AbstractRenderer, CommonInputModel, CommonModel, RenderOutput } from '.
 import { GoRenderer } from '../../src/generators/go/GoRenderer';
 import { CSharpRenderer } from '../../src/generators/csharp/CSharpRenderer';
 import { JavaRenderer } from '../../src/generators/java/JavaRenderer';
+import { TypeScriptRenderer } from '../../src/generators/typescript/TypeScriptRenderer';
 import {testOptions, TestGenerator} from './TestGenerator';
 
 export class TestRenderer extends AbstractRenderer {
@@ -14,6 +15,7 @@ export class TestRenderer extends AbstractRenderer {
 }
 
 export class MockJavaRenderer extends JavaRenderer {}
+export class MockTypeScriptRenderer extends TypeScriptRenderer {}
 export class MockGoRenderer extends GoRenderer {}
 export class MockCSharpRenderer extends CSharpRenderer {}
 
diff --git a/test/generators/typescript/TypeScriptConstrainer.spec.ts b/test/generators/typescript/TypeScriptConstrainer.spec.ts
new file mode 100644
index 00000000..d56c9416
--- /dev/null
+++ b/test/generators/typescript/TypeScriptConstrainer.spec.ts
@@ -0,0 +1,128 @@
+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';
+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});
+      expect(type).toEqual(model.name);
+    });
+  });
+  describe('Reference', () => { 
+    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});
+      expect(type).toEqual(model.name);
+    });
+  });
+  describe('Any', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedAnyModel('test', undefined, '');
+      const type = TypeScriptDefaultTypeMapping.Any({constrainedModel: model, renderer});
+      expect(type).toEqual('any');
+    });
+  });
+  describe('Float', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedFloatModel('test', undefined, '');
+      const type = TypeScriptDefaultTypeMapping.Float({constrainedModel: model, renderer});
+      expect(type).toEqual('number');
+    });
+  });
+  describe('Integer', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedIntegerModel('test', undefined, '');
+      const type = TypeScriptDefaultTypeMapping.Integer({constrainedModel: model, renderer});
+      expect(type).toEqual('integer');
+    });
+  });
+  describe('String', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedStringModel('test', undefined, '');
+      const type = TypeScriptDefaultTypeMapping.String({constrainedModel: model, renderer});
+      expect(type).toEqual('string');
+    });
+  });
+  describe('Boolean', () => { 
+    test('should render type', () => {
+      const model = new ConstrainedBooleanModel('test', undefined, '');
+      const type = TypeScriptDefaultTypeMapping.Boolean({constrainedModel: model, renderer});
+      expect(type).toEqual('boolean');
+    });
+  });
+
+  describe('Tuple', () => { 
+    test('should render type', () => {
+      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});
+      expect(type).toEqual('[String]');
+    });
+    test('should render multiple tuple types', () => {
+      const stringModel = new ConstrainedStringModel('test', undefined, 'String');
+      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});
+      expect(type).toEqual('[String, String]');
+    });
+  });
+
+  describe('Array', () => { 
+    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});
+      expect(type).toEqual('String[]');
+    });
+  });
+
+  describe('Enum', () => { 
+    test('should render the constrained name as type', () => {
+      const model = new ConstrainedEnumModel('test', undefined, '', []);
+      const type = TypeScriptDefaultTypeMapping.Enum({constrainedModel: model, renderer});
+      expect(type).toEqual(model.name);
+    });
+  });
+
+  describe('Union', () => { 
+    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});
+      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});
+      expect(type).toEqual('String | String');
+    });
+  });
+
+  describe('Dictionary', () => { 
+    test('should render 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});
+      expect(type).toEqual('{ [name: 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 }');
+    });
+  });
+});
diff --git a/test/generators/typescript/constrainer/EnumConstrainer.spec.ts b/test/generators/typescript/constrainer/EnumConstrainer.spec.ts
new file mode 100644
index 00000000..0ad2fdc8
--- /dev/null
+++ b/test/generators/typescript/constrainer/EnumConstrainer.spec.ts
@@ -0,0 +1,94 @@
+import { TypeScriptDefaultConstraints } from '../../../../src/generators/typescript/TypeScriptConstrainer';
+import {EnumModel} from '../../../../src/models/MetaModel';
+import { ConstrainedEnumModel, ConstrainedEnumValueModel } from '../../../../src';
+import { defaultEnumKeyConstraints, ModelEnumKeyConstraints, DefaultEnumKeyConstraints } from '../../../../src/generators/typescript/constrainer/EnumConstrainer';
+describe('EnumConstrainer', () => {
+  const enumModel = new EnumModel('test', undefined, []);
+  const constrainedEnumModel = new ConstrainedEnumModel('test', undefined, '', []);
+
+  describe('enum keys', () => {
+    test('should never render special chars', () => {
+      const constrainedKey = TypeScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: '%'});
+      expect(constrainedKey).toEqual('PERCENT');
+    });
+    test('should not render number as start char', () => {
+      const constrainedKey = TypeScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: '1'});
+      expect(constrainedKey).toEqual('NUMBER_1');
+    });
+    test('should not contain duplicate keys', () => {
+      const existingConstrainedEnumValueModel = new ConstrainedEnumValueModel('TEST', 'test');
+      const constrainedEnumModel = new ConstrainedEnumModel('test', undefined, '', [existingConstrainedEnumValueModel]);
+      const constrainedKey = TypeScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'TEST'});
+      expect(constrainedKey).toEqual('RESERVED_TEST');
+    });
+    test('should never contain empty keys', () => {
+      const constrainedKey = TypeScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: ''});
+      expect(constrainedKey).toEqual('EMPTY');
+    });
+    test('should use constant naming format', () => {
+      const constrainedKey = TypeScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'some weird_value!"#2'});
+      expect(constrainedKey).toEqual('SOME_SPACE_WEIRD_VALUE_EXCLAMATION_QUOTATION_HASH_2');
+    });
+    test('should never render reserved keywords', () => {
+      const constrainedKey = TypeScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'return'});
+      expect(constrainedKey).toEqual('RESERVED_RETURN');
+    });
+  });
+  describe('enum values', () => {
+    test('should render string values', () => {
+      const constrainedValue = TypeScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: 'string value'});
+      expect(constrainedValue).toEqual('"string value"');
+    });
+    test('should render boolean values', () => {
+      const constrainedValue = TypeScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: true});
+      expect(constrainedValue).toEqual('"true"');
+    });
+    test.skip('should render numbers', () => {
+      const constrainedValue = TypeScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: 123});
+      expect(constrainedValue).toEqual(123);
+    });
+    test.skip('should render object', () => {
+      const constrainedValue = TypeScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: {test: 'test'}});
+      expect(constrainedValue).toEqual('"{\\"test\\":\\"test\\"}"');
+    });
+    test.skip('should render unknown value', () => {
+      const constrainedValue = TypeScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: undefined});
+      expect(constrainedValue).toEqual('"undefined"');
+    });
+  });
+  describe('custom constraints', () => {
+    test('should be able to overwrite all hooks for enum key', () => {
+      const mockedConstraintCallbacks: 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('')
+      };
+      const constrainFunction = defaultEnumKeyConstraints(mockedConstraintCallbacks);
+      constrainFunction({enumModel, constrainedEnumModel, enumKey: ''});
+      //Expect all callbacks to be called
+      for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+    test('should be able to overwrite one hooks for enum key', () => {
+      //All but NAMING_FORMATTER, as we customize that
+      const spies = [
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_SPECIAL_CHAR'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_NUMBER_START_CHAR'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_DUPLICATE_KEYS'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_EMPTY_VALUE'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_RESERVED_KEYWORDS')
+      ];
+      const jestCallback = jest.fn().mockReturnValue('');
+      const constrainFunction = defaultEnumKeyConstraints({NAMING_FORMATTER: jestCallback});
+      const constrainedValue = constrainFunction({enumModel, constrainedEnumModel, enumKey: ''});
+      expect(constrainedValue).toEqual('');
+      for (const jestMockCallback of spies) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+  });
+});
diff --git a/test/generators/typescript/constrainer/ModelNameConstrainer.spec.ts b/test/generators/typescript/constrainer/ModelNameConstrainer.spec.ts
new file mode 100644
index 00000000..2c12e3e8
--- /dev/null
+++ b/test/generators/typescript/constrainer/ModelNameConstrainer.spec.ts
@@ -0,0 +1,57 @@
+import { TypeScriptDefaultConstraints } from '../../../../src/generators/typescript/TypeScriptConstrainer';
+import { DefaultModelNameConstraints, defaultModelNameConstraints, ModelNameConstraints } from '../../../../src/generators/typescript/constrainer/ModelNameConstrainer';
+describe('ModelNameConstrainer', () => {
+  test('should never render special chars', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.modelName({modelName: '%'});
+    expect(constrainedKey).toEqual('Percent');
+  });
+  test('should never render number as start char', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.modelName({modelName: '1'});
+    expect(constrainedKey).toEqual('Number_1');
+  });
+  test('should never contain empty name', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.modelName({modelName: ''});
+    expect(constrainedKey).toEqual('Empty');
+  });
+  test('should use constant naming format', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.modelName({modelName: 'some weird_value!"#2'});
+    expect(constrainedKey).toEqual('SomeWeirdValueExclamationQuotationHash_2');
+  });
+  test('should never render reserved keywords', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.modelName({modelName: 'return'});
+    expect(constrainedKey).toEqual('ReservedReturn');
+  });
+  describe('custom constraints', () => {
+    test('should be able to overwrite all hooks', () => {
+      const mockedConstraintCallbacks: ModelNameConstraints = {
+        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('')
+      };
+      const constrainFunction = defaultModelNameConstraints(mockedConstraintCallbacks);
+      constrainFunction({modelName: ''});
+      //Expect all callbacks to be called
+      for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+    test('should be able to overwrite one hooks', () => {
+      //All but NAMING_FORMATTER, as we customize that
+      const spies = [
+        jest.spyOn(DefaultModelNameConstraints, 'NO_SPECIAL_CHAR'),
+        jest.spyOn(DefaultModelNameConstraints, 'NO_NUMBER_START_CHAR'),
+        jest.spyOn(DefaultModelNameConstraints, 'NO_EMPTY_VALUE'),
+        jest.spyOn(DefaultModelNameConstraints, 'NO_RESERVED_KEYWORDS')
+      ];
+      const jestCallback = jest.fn().mockReturnValue('');
+      const constrainFunction = defaultModelNameConstraints({NAMING_FORMATTER: jestCallback});
+      const constrainedValue = constrainFunction({modelName: ''});
+      expect(constrainedValue).toEqual('');
+      for (const jestMockCallback of spies) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+  });
+});
diff --git a/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts b/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts
new file mode 100644
index 00000000..0ed09d38
--- /dev/null
+++ b/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts
@@ -0,0 +1,70 @@
+import { TypeScriptDefaultConstraints } from '../../../../src/generators/typescript/TypeScriptConstrainer';
+import { ConstrainedObjectModel, ObjectModel } from '../../../../src';
+import { DefaultPropertyKeyConstraints, defaultPropertyKeyConstraints, PropertyKeyConstraintOptions } from '../../../../src/generators/typescript/constrainer/PropertyKeyConstrainer';
+describe('PropertyKeyConstrainer', () => {
+  const objectModel = new ObjectModel('test', undefined, {});
+  const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {});
+
+  test('should never render special chars', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: '%'});
+    expect(constrainedKey).toEqual('Percent');
+  });
+  test('should not render number as start char', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: '1'});
+    expect(constrainedKey).toEqual('Number_1');
+  });
+  test('should never contain empty name', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: ''});
+    expect(constrainedKey).toEqual('Empty');
+  });
+  test('should use constant naming format', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'some weird_value!"#2'});
+    expect(constrainedKey).toEqual('SomeWeirdValueExclamationQuotationHash_2');
+  });
+  test('should not contain duplicate properties', () => {
+    const objectModel = new ObjectModel('test', undefined, {});
+    const propertyModel = new ConstrainedObjectModel('SomeProperty', undefined, '', {});
+    const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {SomeProperty: propertyModel});
+    const constrainedKey = TypeScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'SomeProperty'});
+    expect(constrainedKey).toEqual('ReservedSomeProperty');
+  });
+  test('should never render reserved keywords', () => {
+    const constrainedKey = TypeScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'return'});
+    expect(constrainedKey).toEqual('ReservedReturn');
+  });
+  describe('custom constraints', () => {
+    test('should be able to overwrite all hooks', () => {
+      const mockedConstraintCallbacks: 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('')
+      };
+      const constrainFunction = defaultPropertyKeyConstraints(mockedConstraintCallbacks);
+      constrainFunction({constrainedObjectModel, objectModel, propertyKey: ''});
+      //Expect all callbacks to be called
+      for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+    test('should be able to overwrite one hooks', () => {
+      //All but NAMING_FORMATTER, as we customize that
+      const spies = [
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_SPECIAL_CHAR'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_NUMBER_START_CHAR'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_EMPTY_VALUE'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_RESERVED_KEYWORDS'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_DUPLICATE_PROPERTIES')
+      ];
+      const jestCallback = jest.fn().mockReturnValue('');
+      const constrainFunction = defaultPropertyKeyConstraints({NAMING_FORMATTER: jestCallback});
+      const constrainedValue = constrainFunction({constrainedObjectModel, objectModel, propertyKey: ''});
+      expect(constrainedValue).toEqual('');
+      for (const jestMockCallback of spies) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+  });
+});