From 28e7dbd3d38ae430a5a9c17a36e9321f74476087 Mon Sep 17 00:00:00 2001
From: Kamil Rojewski <krojew@users.noreply.github.com>
Date: Mon, 10 Apr 2017 19:01:13 +0200
Subject: [PATCH] TypeScript support (#4232)

* Eclipse ignore

* TypeScript support

* Prefixing enums

* Test results

* Merged JS and TS generators

* Fixed AppVeyor build problems

* Fixed more AppVeyor build problems

* Fixed more AppVeyor build problems

* Changed TS flag to options struct

* Storing options by value

* Removed unneeded const

* Re-export support for unions

* Uint support

* Casting bools to numbers for mutation

* TS shell tests

* Reverted generates js test file to original version

* Backing up js tests and properly generating test data
---
 .gitignore                                    |    5 +-
 include/flatbuffers/code_generators.h         |    2 +
 include/flatbuffers/idl.h                     |    9 +-
 js/flatbuffers.js                             |   29 +
 src/code_generators.cpp                       |   14 +
 src/flatc.cpp                                 |    6 +
 src/flatc_main.cpp                            |    5 +
 src/idl_gen_js.cpp                            |  537 +++++-
 tests/TypeScriptTest.sh                       |   25 +
 tests/generate_code.sh                        |    4 +-
 tests/monster_test_generated.ts               | 1683 +++++++++++++++++
 .../namespace_test1_generated.ts              |  180 ++
 .../namespace_test2_generated.ts              |  277 +++
 13 files changed, 2672 insertions(+), 104 deletions(-)
 create mode 100755 tests/TypeScriptTest.sh
 create mode 100644 tests/monster_test_generated.ts
 create mode 100644 tests/namespace_test/namespace_test1_generated.ts
 create mode 100644 tests/namespace_test/namespace_test2_generated.ts

diff --git a/.gitignore b/.gitignore
index 77a77b9a..c6c3067a 100755
--- a/.gitignore
+++ b/.gitignore
@@ -66,5 +66,8 @@ build/VS2010/FlatBuffers.opensdf
 build/VS2010/ipch/**/*.ipch
 *.so
 Testing/Temporary
+.cproject
+.settings/
+.project
 net/**/obj
-
+node_modules/
diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h
index 16e368ea..3e85df2a 100644
--- a/include/flatbuffers/code_generators.h
+++ b/include/flatbuffers/code_generators.h
@@ -114,6 +114,8 @@ class BaseGenerator {
 
   std::string WrapInNameSpace(const Definition &def) const;
 
+  std::string GetNameSpace(const Definition &def) const;
+
   const Parser &parser_;
   const std::string &path_;
   const std::string &file_name_;
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index deb1edf8..9978d34e 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -358,7 +358,9 @@ struct IDLOptions {
   bool allow_non_utf8;
   std::string include_prefix;
   bool binary_schema_comments;
+  bool skip_flatbuffers_import;
   std::string go_namespace;
+  bool reexport_ts_modules;
 
   // Possible options for the more general generator below.
   enum Language {
@@ -371,6 +373,7 @@ struct IDLOptions {
     kPhp    = 1 << 6,
     kJson   = 1 << 7,
     kBinary = 1 << 8,
+    kTs     = 1 << 9,
     kMAX
   };
 
@@ -400,6 +403,8 @@ struct IDLOptions {
       union_value_namespacing(true),
       allow_non_utf8(false),
       binary_schema_comments(false),
+      skip_flatbuffers_import(false),
+      reexport_ts_modules(true),
       lang(IDLOptions::kJava),
       lang_to_generate(0) {}
 };
@@ -650,7 +655,7 @@ extern bool GenerateCPP(const Parser &parser,
                         const std::string &path,
                         const std::string &file_name);
 
-// Generate JavaScript code from the definitions in the Parser object.
+// Generate JavaScript or TypeScript code from the definitions in the Parser object.
 // See idl_gen_js.
 extern std::string GenerateJS(const Parser &parser);
 extern bool GenerateJS(const Parser &parser,
@@ -701,7 +706,7 @@ extern bool GenerateFBS(const Parser &parser,
                         const std::string &path,
                         const std::string &file_name);
 
-// Generate a make rule for the generated JavaScript code.
+// Generate a make rule for the generated JavaScript or TypeScript code.
 // See idl_gen_js.cpp.
 extern std::string JSMakeRule(const Parser &parser,
                               const std::string &path,
diff --git a/js/flatbuffers.js b/js/flatbuffers.js
index 4a2bd236..2bb36eac 100644
--- a/js/flatbuffers.js
+++ b/js/flatbuffers.js
@@ -963,6 +963,15 @@ flatbuffers.ByteBuffer.prototype.writeInt16 = function(offset, value) {
   this.bytes_[offset + 1] = value >> 8;
 };
 
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint16 = function(offset, value) {
+    this.bytes_[offset] = value;
+    this.bytes_[offset + 1] = value >> 8;
+};
+
 /**
  * @param {number} offset
  * @param {number} value
@@ -974,6 +983,17 @@ flatbuffers.ByteBuffer.prototype.writeInt32 = function(offset, value) {
   this.bytes_[offset + 3] = value >> 24;
 };
 
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint32 = function(offset, value) {
+    this.bytes_[offset] = value;
+    this.bytes_[offset + 1] = value >> 8;
+    this.bytes_[offset + 2] = value >> 16;
+    this.bytes_[offset + 3] = value >> 24;
+};
+
 /**
  * @param {number} offset
  * @param {flatbuffers.Long} value
@@ -983,6 +1003,15 @@ flatbuffers.ByteBuffer.prototype.writeInt64 = function(offset, value) {
   this.writeInt32(offset + 4, value.high);
 };
 
+/**
+ * @param {number} offset
+ * @param {flatbuffers.Long} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint64 = function(offset, value) {
+    this.writeUint32(offset, value.low);
+    this.writeUint32(offset + 4, value.high);
+};
+
 /**
  * @param {number} offset
  * @param {number} value
diff --git a/src/code_generators.cpp b/src/code_generators.cpp
index 92954699..b9e73c62 100644
--- a/src/code_generators.cpp
+++ b/src/code_generators.cpp
@@ -135,6 +135,20 @@ std::string BaseGenerator::WrapInNameSpace(const Definition &def) const {
   return WrapInNameSpace(def.defined_namespace, def.name);
 }
 
+std::string BaseGenerator::GetNameSpace(const Definition &def) const {
+  const Namespace *ns = def.defined_namespace;
+  if (CurrentNameSpace() == ns) return "";
+  std::string qualified_name = qualifying_start_;
+  for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
+    qualified_name += *it;
+    if (std::next(it) != ns->components.end()) {
+        qualified_name += qualifying_separator_;
+    }
+  }
+
+  return qualified_name;
+}
+
 // Generate a documentation comment, if available.
 void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
                 const CommentConfig *config, const char *prefix) {
diff --git a/src/flatc.cpp b/src/flatc.cpp
index f12b3d08..7e324eb1 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -103,6 +103,8 @@ std::string FlatCompiler::GetUsageString(const char* program_name) const {
       "    PATH             \n"
       "  --include-prefix   Prefix this path to any generated include statements.\n"
       "    PATH\n"
+      "  --no-fb-import     Don't include flatbuffers import statement for TypeScript.\n"
+      "  --no-ts-reexport   Don't re-export imported dependencies for TypeScript.\n"
       "FILEs may be schemas, or JSON files (conforming to preceding schema)\n"
       "FILEs after the -- must be binary flatbuffer format files.\n"
       "Output files are named using the base file name of the input,\n"
@@ -216,6 +218,10 @@ int FlatCompiler::Compile(int argc, const char** argv) {
         grpc_enabled = true;
       } else if(arg == "--bfbs-comments") {
         opts.binary_schema_comments = true;
+      } else if(arg == "--no-fb-import") {
+        opts.skip_flatbuffers_import = true;
+      } else if(arg == "--no-ts-reexport") {
+        opts.reexport_ts_modules = false;
       } else {
         for (size_t i = 0; i < params_.num_generators; ++i) {
           if (arg == params_.generators[i].generator_opt_long ||
diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp
index f4d9557b..d838bac8 100644
--- a/src/flatc_main.cpp
+++ b/src/flatc_main.cpp
@@ -76,6 +76,11 @@ int main(int argc, const char *argv[]) {
       flatbuffers::IDLOptions::kJs,
       "Generate JavaScript code for tables/structs",
       flatbuffers::JSMakeRule },
+    { flatbuffers::GenerateJS,       "-T", "--ts", "TypeScript",
+      nullptr,
+      flatbuffers::IDLOptions::kTs,
+      "Generate TypeScript code for tables/structs",
+      flatbuffers::JSMakeRule },
     { flatbuffers::GenerateGeneral,  "-n", "--csharp", "C#",
       nullptr,
       flatbuffers::IDLOptions::kCSharp,
diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp
index e1daf0af..e39387e6 100644
--- a/src/idl_gen_js.cpp
+++ b/src/idl_gen_js.cpp
@@ -15,6 +15,9 @@
  */
 
 // independent from idl_parser, since this code is not needed for most clients
+#include <unordered_set>
+#include <unordered_map>
+#include <cassert>
 
 #include "flatbuffers/flatbuffers.h"
 #include "flatbuffers/idl.h"
@@ -23,9 +26,43 @@
 
 namespace flatbuffers {
 
+const std::string kGeneratedFileNamePostfix = "_generated";
+
+struct JsLanguageParameters {
+  IDLOptions::Language language;
+  std::string file_extension;
+};
+
+struct ReexportDescription {
+  std::string symbol;
+  std::string source_namespace;
+  std::string target_namespace;
+};
+
+const JsLanguageParameters& GetJsLangParams(IDLOptions::Language lang) {
+  static JsLanguageParameters js_language_parameters[] = {
+    {
+      IDLOptions::kJs,
+      ".js",
+    },
+    {
+      IDLOptions::kTs,
+      ".ts",
+    },
+  };
+
+  if (lang == IDLOptions::kJs) {
+    return js_language_parameters[0];
+  } else {
+    assert(lang == IDLOptions::kTs);
+    return js_language_parameters[1];
+  }
+}
+
 static std::string GeneratedFileName(const std::string &path,
-                                     const std::string &file_name) {
-  return path + file_name + "_generated.js";
+                                     const std::string &file_name,
+                                     const JsLanguageParameters &lang) {
+  return path + file_name + kGeneratedFileNamePostfix + lang.file_extension;
 }
 
 namespace js {
@@ -33,17 +70,28 @@ namespace js {
 // and tables) and output them to a single file.
 class JsGenerator : public BaseGenerator {
  public:
+  typedef std::unordered_set<std::string> imported_fileset;
+  typedef std::unordered_multimap<std::string, ReexportDescription> reexport_map;
+
   JsGenerator(const Parser &parser, const std::string &path,
               const std::string &file_name)
-      : BaseGenerator(parser, path, file_name, "", "."){};
+      : BaseGenerator(parser, path, file_name, "", "."),
+        lang_(GetJsLangParams(parser_.opts.lang))
+  {
+  };
   // Iterate through all definitions we haven't generate code for (enums,
   // structs, and tables) and output them to a single file.
   bool generate() {
     if (IsEverythingGenerated()) return true;
 
-    std::string enum_code, struct_code, exports_code, code;
-    generateEnums(&enum_code, &exports_code);
-    generateStructs(&struct_code, &exports_code);
+    imported_fileset imported_files;
+    reexport_map reexports;
+
+    std::string enum_code, struct_code, import_code, exports_code, code;
+    generateEnums(&enum_code, &exports_code, reexports);
+    generateStructs(&struct_code, &exports_code, imported_files);
+    generateImportDependencies(&import_code, imported_files);
+    generateReexports(&import_code, reexports, imported_files);
 
     code = code + "// " + FlatBuffersGeneratedWarning();
 
@@ -51,38 +99,90 @@ class JsGenerator : public BaseGenerator {
     GenNamespaces(&code, &exports_code);
 
     // Output the main declaration code from above.
+    code += import_code;
+
     code += enum_code;
     code += struct_code;
 
-    if (!exports_code.empty() && !parser_.opts.skip_js_exports) {
+    if (lang_.language == IDLOptions::kJs && !exports_code.empty() && !parser_.opts.skip_js_exports) {
       code += "// Exports for Node.js and RequireJS\n";
       code += exports_code;
     }
 
-    return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
+    return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code, false);
   }
 
  private:
+  JsLanguageParameters lang_;
+
+  // Generate code for imports
+  void generateImportDependencies(std::string *code_ptr, const imported_fileset &imported_files) {
+    std::string &code = *code_ptr;
+    for (auto it = imported_files.begin(); it != imported_files.end(); ++it) {
+      const auto &file = *it;
+      const auto basename =
+          flatbuffers::StripPath(flatbuffers::StripExtension(file));
+      if (basename != file_name_) {
+        const auto file_name = basename + kGeneratedFileNamePostfix;
+        code += GenPrefixedImport(file, file_name);
+      }
+    }
+  }
+
+  // Generate reexports, which might not have been explicitly imported using the "export import" trick
+  void generateReexports(std::string *code_ptr,
+                         const reexport_map &reexports,
+                         imported_fileset imported_files) {
+      if (!parser_.opts.reexport_ts_modules || lang_.language != IDLOptions::kTs) {
+          return;
+      }
+
+      std::string &code = *code_ptr;
+      for (auto it = reexports.begin(); it != reexports.end(); ++it) {
+        const auto &file = *it;
+        const auto basename =
+            flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
+        if (basename != file_name_) {
+          const auto file_name = basename + kGeneratedFileNamePostfix;
+
+          if (imported_files.find(file.first) == imported_files.end()) {
+            code += GenPrefixedImport(file.first, file_name);
+            imported_files.emplace(file.first);
+          }
+
+          code += "export namespace " + file.second.target_namespace + " { \n";
+          code += "export import " + file.second.symbol + " = ";
+          code += GenFileNamespacePrefix(file.first) + "." + file.second.source_namespace + "." + file.second.symbol + "; }\n";
+        }
+      }
+  }
+
   // Generate code for all enums.
   void generateEnums(std::string *enum_code_ptr,
-                     std::string *exports_code_ptr) {
+                     std::string *exports_code_ptr,
+                     reexport_map &reexports) {
     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
          ++it) {
       auto &enum_def = **it;
-      GenEnum(enum_def, enum_code_ptr, exports_code_ptr);
+      GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports);
     }
   }
 
   // Generate code for all structs.
   void generateStructs(std::string *decl_code_ptr,
-                       std::string *exports_code_ptr) {
+                       std::string *exports_code_ptr,
+                       imported_fileset &imported_files) {
     for (auto it = parser_.structs_.vec.begin();
          it != parser_.structs_.vec.end(); ++it) {
       auto &struct_def = **it;
-      GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr);
+      GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr, imported_files);
     }
   }
   void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
+  if (lang_.language == IDLOptions::kTs && parser_.opts.skip_flatbuffers_import) {
+    return;
+  }
+
   std::set<std::string> namespaces;
 
   for (auto it = parser_.namespaces_.begin();
@@ -110,16 +210,23 @@ class JsGenerator : public BaseGenerator {
   std::string &exports = *exports_ptr;
   for (auto it = sorted_namespaces.begin();
        it != sorted_namespaces.end(); it++) {
-    code += "/**\n * @const\n * @namespace\n */\n";
-    if (it->find('.') == std::string::npos) {
-      code += "var ";
-      if(parser_.opts.use_goog_js_export_format) {
-        exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
-      } else {
-        exports += "this." + *it + " = " + *it + ";\n";
+    if (lang_.language == IDLOptions::kTs) {
+      if (it->find('.') == std::string::npos) {
+        code += "import { flatbuffers } from \"./flatbuffers\"\n";
+        break;
+      }
+    } else {
+      code += "/**\n * @const\n * @namespace\n */\n";
+      if (it->find('.') == std::string::npos) {
+        code += "var ";
+        if(parser_.opts.use_goog_js_export_format) {
+          exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
+        } else {
+          exports += "this." + *it + " = " + *it + ";\n";
+        }
       }
+      code += *it + " = " + *it + " || {};\n\n";
     }
-    code += *it + " = " + *it + " || {};\n\n";
   }
 }
 
@@ -169,21 +276,25 @@ static void GenDocComment(std::string *code_ptr,
 
 // Generate an enum declaration and an enum string lookup table.
 void GenEnum(EnumDef &enum_def, std::string *code_ptr,
-                    std::string *exports_ptr) {
+             std::string *exports_ptr, reexport_map &reexports) {
   if (enum_def.generated) return;
   std::string &code = *code_ptr;
   std::string &exports = *exports_ptr;
   GenDocComment(enum_def.doc_comment, code_ptr, "@enum");
-  if (enum_def.defined_namespace->components.empty()) {
-    code += "var ";
-    if(parser_.opts.use_goog_js_export_format) {
-      exports += "goog.exportSymbol('" + enum_def.name + "', " + enum_def.name +
-        ");\n";
-    } else {
-      exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
+  if (lang_.language == IDLOptions::kTs) {
+    code += "export namespace " + GetNameSpace(enum_def) + "{\n" + "export enum " + enum_def.name + "{\n";
+  } else {
+    if (enum_def.defined_namespace->components.empty()) {
+      code += "var ";
+      if(parser_.opts.use_goog_js_export_format) {
+        exports += "goog.exportSymbol('" + enum_def.name + "', " + enum_def.name +
+          ");\n";
+      } else {
+        exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
+      }
     }
+    code += WrapInNameSpace(enum_def) + " = {\n";
   }
-  code += WrapInNameSpace(enum_def) + " = {\n";
   for (auto it = enum_def.vals.vec.begin();
        it != enum_def.vals.vec.end(); ++it) {
     auto &ev = **it;
@@ -193,10 +304,20 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr,
       }
       GenDocComment(ev.doc_comment, code_ptr, "", "  ");
     }
-    code += "  " + ev.name + ": " + NumToString(ev.value);
+    code += "  " + ev.name + ((lang_.language == IDLOptions::kTs) ? ("= ") : (": ")) + NumToString(ev.value);
     code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
+
+    if (ev.struct_def) {
+        ReexportDescription desc = { ev.name, GetNameSpace(*ev.struct_def), GetNameSpace(enum_def) };
+        reexports.insert(std::make_pair(ev.struct_def->file, std::move(desc)));
+    }
+  }
+
+  if (lang_.language == IDLOptions::kTs) {
+    code += "}};\n\n";
+  } else {
+    code += "};\n\n";
   }
-  code += "};\n\n";
 }
 
 static std::string GenType(const Type &type) {
@@ -244,7 +365,11 @@ std::string GenDefaultValue(const Value &value, const std::string &context) {
   if (value.type.enum_def) {
     if (auto val = value.type.enum_def->ReverseLookup(
         atoi(value.constant.c_str()), false)) {
-      return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
+      if (lang_.language == IDLOptions::kTs) {
+        return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def), value.type.enum_def->file) + "." + val->name;
+      } else {
+        return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
+      }
     } else {
       return "/** @type {" + WrapInNameSpace(*value.type.enum_def) + "} */ ("
         + value.constant + ")";
@@ -322,6 +447,24 @@ static std::string MaybeScale(T value) {
   return value != 1 ? " * " + NumToString(value) : "";
 }
 
+static std::string GenFileNamespacePrefix(const std::string &file) {
+  return "NS" + std::to_string(static_cast<unsigned long long>(std::hash<std::string>()(file)));
+}
+
+static std::string GenPrefixedImport(const std::string &full_file_name,
+                                     const std::string &base_file_name) {
+  return "import * as "+ GenFileNamespacePrefix(full_file_name) + " from \"./" + base_file_name + "\";\n";
+}
+
+// Adds a source-dependent prefix, for of import * statements.
+std::string GenPrefixedTypeName(const std::string &typeName, const std::string &file) {
+  const auto basename = flatbuffers::StripPath(flatbuffers::StripExtension(file));
+  if (basename == file_name_) {
+    return typeName;
+  }
+  return GenFileNamespacePrefix(file) + "." + typeName;
+}
+
 void GenStructArgs(const StructDef &struct_def,
                           std::string *annotations,
                           std::string *arguments,
@@ -338,7 +481,12 @@ void GenStructArgs(const StructDef &struct_def,
     } else {
       *annotations += "@param {" + GenTypeName(field.value.type, true);
       *annotations += "} " + nameprefix + field.name + "\n";
-      *arguments += ", " + nameprefix + field.name;
+
+      if (lang_.language == IDLOptions::kTs) {
+          *arguments += ", " + nameprefix + field.name + ": " + GenTypeName(field.value.type, true);
+      } else {
+          *arguments += ", " + nameprefix + field.name;
+      }
     }
   }
 }
@@ -373,37 +521,58 @@ static void GenStructBody(const StructDef &struct_def,
 }
 
 // Generate an accessor struct with constructor for a flatbuffers struct.
-void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr) {
+void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr,
+               imported_fileset &imported_files) {
   if (struct_def.generated) return;
   std::string &code = *code_ptr;
   std::string &exports = *exports_ptr;
 
+  std::string object_name;
+
   // Emit constructor
-  bool isStatement = struct_def.defined_namespace->components.empty();
-  std::string object_name = WrapInNameSpace(struct_def);
-  GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
-  if (isStatement) {
-    if(parser_.opts.use_goog_js_export_format) {
-      exports += "goog.exportSymbol('" + struct_def.name + "', " +
-        struct_def.name + ");\n";
+  if (lang_.language == IDLOptions::kTs) {
+    object_name = struct_def.name;
+    std::string object_namespace = GetNameSpace(struct_def);
+    GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
+    code += "export namespace " + object_namespace + "{\n";
+    code += "export class " + struct_def.name;
+    code += " {\n";
+    code += "  /**\n";
+    code += "   * @type {flatbuffers.ByteBuffer}\n";
+    code += "   */\n";
+    code += "  bb: flatbuffers.ByteBuffer= null;\n";
+    code += "\n";
+    code += "  /**\n";
+    code += "   * @type {number}\n";
+    code += "   */\n";
+    code += "  bb_pos:number = 0;\n";
+  } else {
+    bool isStatement = struct_def.defined_namespace->components.empty();
+    object_name = WrapInNameSpace(struct_def);
+    GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
+    if (isStatement) {
+      if(parser_.opts.use_goog_js_export_format) {
+        exports += "goog.exportSymbol('" + struct_def.name + "', " +
+          struct_def.name + ");\n";
+      } else {
+        exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
+      }
+      code += "function " + object_name;
     } else {
-      exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
+      code += object_name + " = function";
     }
-    code += "function " + object_name;
-  } else {
-    code += object_name + " = function";
-  }
-  code += "() {\n";
-  code += "  /**\n";
-  code += "   * @type {flatbuffers.ByteBuffer}\n";
-  code += "   */\n";
-  code += "  this.bb = null;\n";
-  code += "\n";
-  code += "  /**\n";
-  code += "   * @type {number}\n";
-  code += "   */\n";
-  code += "  this.bb_pos = 0;\n";
-  code += isStatement ? "}\n\n" : "};\n\n";
+    code += "() {\n";
+    code += "  /**\n";
+    code += "   * @type {flatbuffers.ByteBuffer}\n";
+    code += "   */\n";
+    code += "  this.bb = null;\n";
+    code += "\n";
+    code += "  /**\n";
+    code += "   * @type {number}\n";
+    code += "   */\n";
+    code += "  this.bb_pos = 0;\n";
+    code += isStatement ? "}\n\n" : "};\n\n";
+  }
 
   // Generate the __init method that sets the field in a pre-existing
   // accessor object. This is to allow object reuse.
@@ -412,7 +581,13 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
   code += " * @param {flatbuffers.ByteBuffer} bb\n";
   code += " * @returns {" + object_name + "}\n";
   code += " */\n";
-  code += object_name + ".prototype.__init = function(i, bb) {\n";
+
+  if (lang_.language == IDLOptions::kTs) {
+    code += "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + " {\n";
+  } else {
+    code += object_name + ".prototype.__init = function(i, bb) {\n";
+  }
+
   code += "  this.bb_pos = i;\n";
   code += "  this.bb = bb;\n";
   code += "  return this;\n";
@@ -425,8 +600,13 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
       "@param {flatbuffers.ByteBuffer} bb\n"
       "@param {" + object_name + "=} obj\n"
       "@returns {" + object_name + "}");
-    code += object_name + ".getRootAs" + struct_def.name;
-    code += " = function(bb, obj) {\n";
+    if (lang_.language == IDLOptions::kTs) {
+      code += "static getRootAs" + struct_def.name;
+      code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + "):" + object_name + " {\n";
+    } else {
+      code += object_name + ".getRootAs" + struct_def.name;
+      code += " = function(bb, obj) {\n";
+    }
     code += "  return (obj || new " + object_name;
     code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
     code += "};\n\n";
@@ -437,7 +617,12 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
       GenDocComment(code_ptr,
         "@param {flatbuffers.ByteBuffer} bb\n"
         "@returns {boolean}");
-      code += object_name + ".bufferHasIdentifier = function(bb) {\n";
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {\n";
+      } else {
+        code += object_name + ".bufferHasIdentifier = function(bb) {\n";
+      }
+
       code += "  return bb.__has_identifier('" + parser_.file_identifier_;
       code += "');\n};\n\n";
     }
@@ -458,12 +643,29 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
         std::string(field.value.type.base_type == BASE_TYPE_STRING ?
           "@param {flatbuffers.Encoding=} optionalEncoding\n" : "") +
         "@returns {" + GenTypeName(field.value.type, false) + "}");
-      code += object_name + ".prototype." + MakeCamel(field.name, false);
-      code += " = function(";
-      if (field.value.type.base_type == BASE_TYPE_STRING) {
-        code += "optionalEncoding";
+      if (lang_.language == IDLOptions::kTs) {
+        std::string prefix = MakeCamel(field.name, false) + "(";
+        if (field.value.type.base_type == BASE_TYPE_STRING) {
+          code += prefix + "):string\n";
+          code += prefix + "optionalEncoding:flatbuffers.Encoding"+"):" + GenTypeName(field.value.type, false)+"\n";
+          code += prefix + "optionalEncoding?:any";
+        } else {
+          code += prefix;
+        }
+        if (field.value.type.enum_def) {
+          code += "):" + GenPrefixedTypeName(GenTypeName(field.value.type, false), field.value.type.enum_def->file) + " {\n";
+        } else {
+          code += "):" + GenTypeName(field.value.type, false) + " {\n";
+        }
+      } else {
+        code += object_name + ".prototype." + MakeCamel(field.name, false);
+        code += " = function(";
+        if (field.value.type.base_type == BASE_TYPE_STRING) {
+          code += "optionalEncoding";
+        }
+        code += ") {\n";
       }
-      code += ") {\n";
+
       if (struct_def.fixed) {
         code += "  return " + GenGetter(field.value.type, "(this.bb_pos" +
           MaybeAdd(field.value.offset) + ")") + ";\n";
@@ -485,8 +687,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
           auto type = WrapInNameSpace(*field.value.type.struct_def);
           GenDocComment(field.doc_comment, code_ptr,
             "@param {" + type + "=} obj\n@returns {" + type + "}");
-          code += object_name + ".prototype." + MakeCamel(field.name, false);
-          code += " = function(obj) {\n";
+          if (lang_.language == IDLOptions::kTs) {
+            type = GenPrefixedTypeName(type, field.value.type.struct_def->file);
+            code += MakeCamel(field.name, false);
+            code += "(obj?:" + type + "):" + type + " {\n";
+          } else {
+            code += object_name + ".prototype." + MakeCamel(field.name, false);
+            code += " = function(obj) {\n";
+          }
+
           if (struct_def.fixed) {
             code += "  return (obj || new " + type;
             code += ").__init(this.bb_pos";
@@ -498,6 +707,11 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
               : "this.bb.__indirect(this.bb_pos + offset)";
             code += ", this.bb) : null;\n";
           }
+
+          if (lang_.language == IDLOptions::kTs) {
+            imported_files.insert(field.value.type.struct_def->file);
+          }
+
           break;
         }
 
@@ -515,14 +729,32 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
           }
           GenDocComment(field.doc_comment, code_ptr, args +
             "@returns {" + vectortypename + "}");
-          code += object_name + ".prototype." + MakeCamel(field.name, false);
-          code += " = function(index";
-          if (vectortype.base_type == BASE_TYPE_STRUCT) {
-            code += ", obj";
-          } else if (vectortype.base_type == BASE_TYPE_STRING) {
-            code += ", optionalEncoding";
+          if (lang_.language == IDLOptions::kTs) {
+            std::string prefix = MakeCamel(field.name, false);
+            prefix += "(index: number";
+            if (vectortype.base_type == BASE_TYPE_STRUCT) {
+              vectortypename = GenPrefixedTypeName(vectortypename, vectortype.struct_def->file);
+              code += prefix + ", obj?:" + vectortypename;
+              imported_files.insert(vectortype.struct_def->file);
+            } else if (vectortype.base_type == BASE_TYPE_STRING) {
+              code += prefix + "):string\n";
+              code += prefix + ",optionalEncoding:flatbuffers.Encoding" + "):" + vectortypename + "\n";
+              code += prefix + ",optionalEncoding?:any";
+            } else {
+              code += prefix;
+            }
+            code += "):" + vectortypename + " {\n";
+          } else {
+            code += object_name + ".prototype." + MakeCamel(field.name, false);
+            code += " = function(index";
+            if (vectortype.base_type == BASE_TYPE_STRUCT) {
+              code += ", obj";
+            } else if (vectortype.base_type == BASE_TYPE_STRING) {
+              code += ", optionalEncoding";
+            }
+            code += ") {\n";
           }
-          code += ") {\n";
+
           if (vectortype.base_type == BASE_TYPE_STRUCT) {
             code += offset_prefix + "(obj || new " + vectortypename;
             code += ").__init(";
@@ -561,8 +793,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
           GenDocComment(field.doc_comment, code_ptr,
             "@param {flatbuffers.Table} obj\n"
             "@returns {?flatbuffers.Table}");
-          code += object_name + ".prototype." + MakeCamel(field.name, false);
-          code += " = function(obj) {\n";
+          if (lang_.language == IDLOptions::kTs) {
+            code += MakeCamel(field.name, false);
+            code += "<T extends flatbuffers.Table>(obj:T):T {\n";
+          } else {
+            code += object_name + ".prototype." + MakeCamel(field.name, false);
+            code += " = function(obj) {\n";
+          }
+
           code += offset_prefix + GenGetter(field.value.type,
             "(obj, this.bb_pos + offset)") + " : null;\n";
           break;
@@ -585,12 +823,31 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
       GenDocComment(code_ptr, annotations +
         "@returns {boolean}");
 
-      code += object_name + ".prototype.mutate_" + field.name + " = function(value) {\n";
+      if (lang_.language == IDLOptions::kTs) {
+        std::string type;
+        if (field.value.type.enum_def) {
+          type = GenPrefixedTypeName(GenTypeName(field.value.type, true), field.value.type.enum_def->file);
+        } else {
+          type = GenTypeName(field.value.type, true);
+        }
+
+        code += "mutate_" + field.name + "(value:" + type + "):boolean {\n";
+      } else {
+        code += object_name + ".prototype.mutate_" + field.name + " = function(value) {\n";
+      }
+
       code += "  var offset = this.bb.__offset(this.bb_pos, " + NumToString(field.value.offset) + ");\n\n";
       code += "  if (offset === 0) {\n";
       code += "    return false;\n";
       code += "  }\n\n";
-      code += "  this.bb.write" + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + offset, value);\n";
+
+      // special case for bools, which are treated as uint8
+      code += "  this.bb.write" + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + offset, ";
+      if (field.value.type.base_type == BASE_TYPE_BOOL && lang_.language == IDLOptions::kTs) {
+          code += "+";
+      }
+
+      code += "value);\n";
       code += "  return true;\n";
       code += "};\n\n";
 
@@ -605,8 +862,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
     if (field.value.type.base_type == BASE_TYPE_VECTOR) {
       // Emit a length helper
       GenDocComment(code_ptr, "@returns {number}");
-      code += object_name + ".prototype." + MakeCamel(field.name, false);
-      code += "Length = function() {\n" + offset_prefix;
+      if (lang_.language == IDLOptions::kTs) {
+        code += MakeCamel(field.name, false);
+        code += "Length():number {\n" + offset_prefix;
+      } else {
+        code += object_name + ".prototype." + MakeCamel(field.name, false);
+        code += "Length = function() {\n" + offset_prefix;
+      }
+
       code += "this.bb.__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
 
       if(parser_.opts.use_goog_js_export_format) {
@@ -619,8 +882,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
       auto vectorType = field.value.type.VectorType();
       if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) {
         GenDocComment(code_ptr, "@returns {" + GenType(vectorType) + "Array}");
-        code += object_name + ".prototype." + MakeCamel(field.name, false);
-        code += "Array = function() {\n" + offset_prefix;
+
+        if (lang_.language == IDLOptions::kTs) {
+          code += MakeCamel(field.name, false);
+          code += "Array():" + GenType(vectorType) + "Array {\n" + offset_prefix;
+        } else {
+          code += object_name + ".prototype." + MakeCamel(field.name, false);
+          code += "Array = function() {\n" + offset_prefix;
+        }
+
         code += "new " + GenType(vectorType) + "Array(this.bb.bytes().buffer, "
           "this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), "
           "this.bb.__vector_len(this.bb_pos + offset)) : null;\n};\n\n";
@@ -641,16 +911,30 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
     GenStructArgs(struct_def, &annotations, &arguments, "");
     GenDocComment(code_ptr, annotations +
       "@returns {flatbuffers.Offset}");
-    code += object_name + ".create" + struct_def.name + " = function(builder";
-    code += arguments + ") {\n";
+
+    if (lang_.language == IDLOptions::kTs) {
+      code += "static create" + struct_def.name + "(builder:flatbuffers.Builder";
+      code += arguments + "):flatbuffers.Offset {\n";
+    } else {
+      code += object_name + ".create" + struct_def.name + " = function(builder";
+      code += arguments + ") {\n";
+    }
+
     GenStructBody(struct_def, &code, "");
     code += "  return builder.offset();\n};\n\n";
   } else {
     // Generate a method to start building a new object
     GenDocComment(code_ptr,
       "@param {flatbuffers.Builder} builder");
-    code += object_name + ".start" + struct_def.name;
-    code += " = function(builder) {\n";
+
+    if (lang_.language == IDLOptions::kTs) {
+      code += "static start" + struct_def.name;
+      code += "(builder:flatbuffers.Builder) {\n";
+    } else {
+      code += object_name + ".start" + struct_def.name;
+      code += " = function(builder) {\n";
+    }
+
     code += "  builder.startObject(" + NumToString(
       struct_def.fields.vec.size()) + ");\n";
     code += "};\n\n";
@@ -670,8 +954,22 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
         "@param {flatbuffers.Builder} builder\n"
         "@param {" + GenTypeName(field.value.type, true) + "} " +
         argname);
-      code += object_name + ".add" + MakeCamel(field.name);
-      code += " = function(builder, " + argname + ") {\n";
+
+      if (lang_.language == IDLOptions::kTs) {
+        std::string argType;
+        if (field.value.type.enum_def) {
+          argType = GenPrefixedTypeName(GenTypeName(field.value.type, true), field.value.type.enum_def->file);
+        } else {
+          argType = GenTypeName(field.value.type, true);
+        }
+
+        code += "static add" + MakeCamel(field.name);
+        code += "(builder:flatbuffers.Builder, " + argname + ":" + argType + ") {\n";
+      } else {
+        code += object_name + ".add" + MakeCamel(field.name);
+        code += " = function(builder, " + argname + ") {\n";
+      }
+
       code += "  builder.addField" + GenWriteMethod(field.value.type) + "(";
       code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
       if (field.value.type.base_type == BASE_TYPE_BOOL) {
@@ -700,8 +998,20 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
             "@param {Array.<" + GenTypeName(vector_type, true) +
             ">} data\n"
             "@returns {flatbuffers.Offset}");
-          code += object_name + ".create" + MakeCamel(field.name);
-          code += "Vector = function(builder, data) {\n";
+
+          if (lang_.language == IDLOptions::kTs) {
+            code += "static create" + MakeCamel(field.name);
+            std::string type = GenTypeName(vector_type, true) + "[]";
+            if (type == "number[]") {
+              type += " | Uint8Array";
+            }
+            code += "Vector(builder:flatbuffers.Builder, data:" + type+"):flatbuffers.Offset {\n";
+            code += "if(!data){\n  return null\n}\n";
+          } else {
+            code += object_name + ".create" + MakeCamel(field.name);
+            code += "Vector = function(builder, data) {\n";
+          }
+
           code += "  builder.startVector(" + NumToString(elem_size);
           code += ", data.length, " + NumToString(alignment) + ");\n";
           code += "  for (var i = data.length - 1; i >= 0; i--) {\n";
@@ -719,8 +1029,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
         GenDocComment(code_ptr,
           "@param {flatbuffers.Builder} builder\n"
           "@param {number} numElems");
-        code += object_name + ".start" + MakeCamel(field.name);
-        code += "Vector = function(builder, numElems) {\n";
+
+        if (lang_.language == IDLOptions::kTs) {
+          code += "static start" + MakeCamel(field.name);
+          code += "Vector(builder:flatbuffers.Builder, numElems:number) {\n";
+        } else {
+          code += object_name + ".start" + MakeCamel(field.name);
+          code += "Vector = function(builder, numElems) {\n";
+        }
+
         code += "  builder.startVector(" + NumToString(elem_size);
         code += ", numElems, " + NumToString(alignment) + ");\n";
         code += "};\n\n";
@@ -731,8 +1048,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
     GenDocComment(code_ptr,
       "@param {flatbuffers.Builder} builder\n"
       "@returns {flatbuffers.Offset}");
-    code += object_name + ".end" + struct_def.name;
-    code += " = function(builder) {\n";
+
+    if (lang_.language == IDLOptions::kTs) {
+      code += "static end" + struct_def.name;
+      code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
+    } else {
+      code += object_name + ".end" + struct_def.name;
+      code += " = function(builder) {\n";
+    }
+
     code += "  var offset = builder.endObject();\n";
     for (auto it = struct_def.fields.vec.begin();
          it != struct_def.fields.vec.end(); ++it) {
@@ -751,8 +1075,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
       GenDocComment(code_ptr,
         "@param {flatbuffers.Builder} builder\n"
         "@param {flatbuffers.Offset} offset");
-      code += object_name + ".finish" + struct_def.name + "Buffer";
-      code += " = function(builder, offset) {\n";
+
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static finish" + struct_def.name + "Buffer";
+        code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
+      } else {
+        code += object_name + ".finish" + struct_def.name + "Buffer";
+        code += " = function(builder, offset) {\n";
+      }
+
       code += "  builder.finish(offset";
       if (!parser_.file_identifier_.empty()) {
         code += ", '" + parser_.file_identifier_ + "'";
@@ -761,6 +1092,10 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
       code += "};\n\n";
     }
   }
+
+  if (lang_.language == IDLOptions::kTs) {
+    code += "}\n}\n";
+  }
 }
 };
 }  // namespace js
@@ -774,15 +1109,19 @@ bool GenerateJS(const Parser &parser, const std::string &path,
 std::string JSMakeRule(const Parser &parser,
                        const std::string &path,
                        const std::string &file_name) {
+  assert(parser.opts.lang <= IDLOptions::kMAX);
+  const auto &lang = GetJsLangParams(parser.opts.lang);
+
   std::string filebase = flatbuffers::StripPath(
       flatbuffers::StripExtension(file_name));
-  std::string make_rule = GeneratedFileName(path, filebase) + ": ";
+  std::string make_rule = GeneratedFileName(path, filebase, lang) + ": ";
+
   auto included_files = parser.GetIncludedFilesRecursive(file_name);
   for (auto it = included_files.begin();
        it != included_files.end(); ++it) {
     make_rule += " " + *it;
   }
-  return make_rule;
+return make_rule;
 }
 
 }  // namespace flatbuffers
diff --git a/tests/TypeScriptTest.sh b/tests/TypeScriptTest.sh
new file mode 100755
index 00000000..4e37451c
--- /dev/null
+++ b/tests/TypeScriptTest.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pushd "$(dirname $0)" >/dev/null
+../flatc --ts --no-fb-import --gen-mutable monster_test.fbs
+../flatc -b monster_test.fbs unicode_test.json
+npm install @types/flatbuffers
+mv monster_test_generated.js monster_test_generated.js.bak
+tsc monster_test_generated.ts
+npm uninstall @types/flatbuffers
+node JavaScriptTest
+mv monster_test_generated.js.bak monster_test_generated.js
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
index a5354ebc..00d87f7c 100755
--- a/tests/generate_code.sh
+++ b/tests/generate_code.sh
@@ -14,8 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
-../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
+../flatc --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
+../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
 ../flatc --cpp -o union_vector ./union_vector/union_vector.fbs
 ../flatc -b --schema --bfbs-comments monster_test.fbs
 cd ../samples
diff --git a/tests/monster_test_generated.ts b/tests/monster_test_generated.ts
new file mode 100644
index 00000000..3ff1bf92
--- /dev/null
+++ b/tests/monster_test_generated.ts
@@ -0,0 +1,1683 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @enum
+ */
+export namespace MyGame.Example{
+export enum Color{
+  Red= 1,
+  Green= 2,
+  Blue= 8
+}};
+
+/**
+ * @enum
+ */
+export namespace MyGame.Example{
+export enum Any{
+  NONE= 0,
+  Monster= 1,
+  TestSimpleTableWithEnum= 2,
+  MyGame_Example2_Monster= 3
+}};
+
+/**
+ * @constructor
+ */
+export namespace MyGame.Example2{
+export class Monster {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Monster}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Monster {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Monster=} obj
+ * @returns {Monster}
+ */
+static getRootAsMonster(bb:flatbuffers.ByteBuffer, obj?:Monster):Monster {
+  return (obj || new Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startMonster(builder:flatbuffers.Builder) {
+  builder.startObject(0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endMonster(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Test {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Test}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Test {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+a():number {
+  return this.bb.readInt16(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_a(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+b():number {
+  return this.bb.readInt8(this.bb_pos + 2);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_b(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 2);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} a
+ * @param {number} b
+ * @returns {flatbuffers.Offset}
+ */
+static createTest(builder:flatbuffers.Builder, a: number, b: number):flatbuffers.Offset {
+  builder.prep(2, 4);
+  builder.pad(1);
+  builder.writeInt8(b);
+  builder.writeInt16(a);
+  return builder.offset();
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class TestSimpleTableWithEnum {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {TestSimpleTableWithEnum}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TestSimpleTableWithEnum {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {TestSimpleTableWithEnum=} obj
+ * @returns {TestSimpleTableWithEnum}
+ */
+static getRootAsTestSimpleTableWithEnum(bb:flatbuffers.ByteBuffer, obj?:TestSimpleTableWithEnum):TestSimpleTableWithEnum {
+  return (obj || new TestSimpleTableWithEnum).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {MyGame.Example.Color}
+ */
+color():MyGame.Example.Color {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? /** @type {MyGame.Example.Color} */ (this.bb.readInt8(this.bb_pos + offset)) : MyGame.Example.Color.Green;
+};
+
+/**
+ * @param {MyGame.Example.Color} value
+ * @returns {boolean}
+ */
+mutate_color(value:MyGame.Example.Color):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startTestSimpleTableWithEnum(builder:flatbuffers.Builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Color} color
+ */
+static addColor(builder:flatbuffers.Builder, color:MyGame.Example.Color) {
+  builder.addFieldInt8(0, color, MyGame.Example.Color.Green);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endTestSimpleTableWithEnum(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Vec3 {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Vec3}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Vec3 {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+x():number {
+  return this.bb.readFloat32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_x(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+y():number {
+  return this.bb.readFloat32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_y(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+z():number {
+  return this.bb.readFloat32(this.bb_pos + 8);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_z(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+test1():number {
+  return this.bb.readFloat64(this.bb_pos + 16);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_test1(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {MyGame.Example.Color}
+ */
+test2():MyGame.Example.Color {
+  return /** @type {MyGame.Example.Color} */ (this.bb.readInt8(this.bb_pos + 24));
+};
+
+/**
+ * @param {MyGame.Example.Color} value
+ * @returns {boolean}
+ */
+mutate_test2(value:MyGame.Example.Color):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {MyGame.Example.Test=} obj
+ * @returns {MyGame.Example.Test}
+ */
+test3(obj?:MyGame.Example.Test):MyGame.Example.Test {
+  return (obj || new MyGame.Example.Test).__init(this.bb_pos + 26, this.bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} test1
+ * @param {MyGame.Example.Color} test2
+ * @param {number} test3_a
+ * @param {number} test3_b
+ * @returns {flatbuffers.Offset}
+ */
+static createVec3(builder:flatbuffers.Builder, x: number, y: number, z: number, test1: number, test2: MyGame.Example.Color, test3_a: number, test3_b: number):flatbuffers.Offset {
+  builder.prep(16, 32);
+  builder.pad(2);
+  builder.prep(2, 4);
+  builder.pad(1);
+  builder.writeInt8(test3_b);
+  builder.writeInt16(test3_a);
+  builder.pad(1);
+  builder.writeInt8(test2);
+  builder.writeFloat64(test1);
+  builder.pad(4);
+  builder.writeFloat32(z);
+  builder.writeFloat32(y);
+  builder.writeFloat32(x);
+  return builder.offset();
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Ability {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Ability}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Ability {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+id():number {
+  return this.bb.readUint32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_id(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+distance():number {
+  return this.bb.readUint32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_distance(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} id
+ * @param {number} distance
+ * @returns {flatbuffers.Offset}
+ */
+static createAbility(builder:flatbuffers.Builder, id: number, distance: number):flatbuffers.Offset {
+  builder.prep(4, 8);
+  builder.writeInt32(distance);
+  builder.writeInt32(id);
+  return builder.offset();
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Stat {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Stat}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Stat {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Stat=} obj
+ * @returns {Stat}
+ */
+static getRootAsStat(bb:flatbuffers.ByteBuffer, obj?:Stat):Stat {
+  return (obj || new Stat).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array}
+ */
+id():string
+id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array
+id(optionalEncoding?:any):string|Uint8Array {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+val():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_val(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+count():number {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.readUint16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_count(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startStat(builder:flatbuffers.Builder) {
+  builder.startObject(3);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} idOffset
+ */
+static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, idOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} val
+ */
+static addVal(builder:flatbuffers.Builder, val:flatbuffers.Long) {
+  builder.addFieldInt64(1, val, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} count
+ */
+static addCount(builder:flatbuffers.Builder, count:number) {
+  builder.addFieldInt16(2, count, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endStat(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * an example documentation comment: monster object
+ *
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Monster {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Monster}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Monster {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Monster=} obj
+ * @returns {Monster}
+ */
+static getRootAsMonster(bb:flatbuffers.ByteBuffer, obj?:Monster):Monster {
+  return (obj || new Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {boolean}
+ */
+static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {
+  return bb.__has_identifier('MONS');
+};
+
+/**
+ * @param {MyGame.Example.Vec3=} obj
+ * @returns {MyGame.Example.Vec3}
+ */
+pos(obj?:MyGame.Example.Vec3):MyGame.Example.Vec3 {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? (obj || new MyGame.Example.Vec3).__init(this.bb_pos + offset, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+mana():number {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.readInt16(this.bb_pos + offset) : 150;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_mana(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+hp():number {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.readInt16(this.bb_pos + offset) : 100;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_hp(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array}
+ */
+name():string
+name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array
+name(optionalEncoding?:any):string|Uint8Array {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+  return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+inventory(index: number):number {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+  return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+inventoryLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+inventoryArray():Uint8Array {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+  return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @returns {MyGame.Example.Color}
+ */
+color():MyGame.Example.Color {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+  return offset ? /** @type {MyGame.Example.Color} */ (this.bb.readInt8(this.bb_pos + offset)) : MyGame.Example.Color.Blue;
+};
+
+/**
+ * @param {MyGame.Example.Color} value
+ * @returns {boolean}
+ */
+mutate_color(value:MyGame.Example.Color):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {MyGame.Example.Any}
+ */
+testType():MyGame.Example.Any {
+  var offset = this.bb.__offset(this.bb_pos, 18);
+  return offset ? /** @type {MyGame.Example.Any} */ (this.bb.readUint8(this.bb_pos + offset)) : MyGame.Example.Any.NONE;
+};
+
+/**
+ * @param {MyGame.Example.Any} value
+ * @returns {boolean}
+ */
+mutate_test_type(value:MyGame.Example.Any):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 18);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Table} obj
+ * @returns {?flatbuffers.Table}
+ */
+test<T extends flatbuffers.Table>(obj:T):T {
+  var offset = this.bb.__offset(this.bb_pos, 20);
+  return offset ? this.bb.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Test=} obj
+ * @returns {MyGame.Example.Test}
+ */
+test4(index: number, obj?:MyGame.Example.Test):MyGame.Example.Test {
+  var offset = this.bb.__offset(this.bb_pos, 22);
+  return offset ? (obj || new MyGame.Example.Test).__init(this.bb.__vector(this.bb_pos + offset) + index * 4, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+test4Length():number {
+  var offset = this.bb.__offset(this.bb_pos, 22);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array}
+ */
+testarrayofstring(index: number):string
+testarrayofstring(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array
+testarrayofstring(index: number,optionalEncoding?:any):string|Uint8Array {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayofstringLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * an example documentation comment: this will end up in the generated code
+ * multiline too
+ *
+ * @param {number} index
+ * @param {MyGame.Example.Monster=} obj
+ * @returns {MyGame.Example.Monster}
+ */
+testarrayoftables(index: number, obj?:MyGame.Example.Monster):MyGame.Example.Monster {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? (obj || new MyGame.Example.Monster).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayoftablesLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {MyGame.Example.Monster=} obj
+ * @returns {MyGame.Example.Monster}
+ */
+enemy(obj?:MyGame.Example.Monster):MyGame.Example.Monster {
+  var offset = this.bb.__offset(this.bb_pos, 28);
+  return offset ? (obj || new MyGame.Example.Monster).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+testnestedflatbuffer(index: number):number {
+  var offset = this.bb.__offset(this.bb_pos, 30);
+  return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+testnestedflatbufferLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 30);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+testnestedflatbufferArray():Uint8Array {
+  var offset = this.bb.__offset(this.bb_pos, 30);
+  return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {MyGame.Example.Stat=} obj
+ * @returns {MyGame.Example.Stat}
+ */
+testempty(obj?:MyGame.Example.Stat):MyGame.Example.Stat {
+  var offset = this.bb.__offset(this.bb_pos, 32);
+  return offset ? (obj || new MyGame.Example.Stat).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @returns {boolean}
+ */
+testbool():boolean {
+  var offset = this.bb.__offset(this.bb_pos, 34);
+  return offset ? !!this.bb.readInt8(this.bb_pos + offset) : false;
+};
+
+/**
+ * @param {boolean} value
+ * @returns {boolean}
+ */
+mutate_testbool(value:boolean):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 34);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, +value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testhashs32Fnv1():number {
+  var offset = this.bb.__offset(this.bb_pos, 36);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testhashs32_fnv1(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 36);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testhashu32Fnv1():number {
+  var offset = this.bb.__offset(this.bb_pos, 38);
+  return offset ? this.bb.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testhashu32_fnv1(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 38);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+testhashs64Fnv1():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 40);
+  return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_testhashs64_fnv1(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 40);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+testhashu64Fnv1():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 42);
+  return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_testhashu64_fnv1(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 42);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testhashs32Fnv1a():number {
+  var offset = this.bb.__offset(this.bb_pos, 44);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testhashs32_fnv1a(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 44);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testhashu32Fnv1a():number {
+  var offset = this.bb.__offset(this.bb_pos, 46);
+  return offset ? this.bb.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testhashu32_fnv1a(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 46);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+testhashs64Fnv1a():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 48);
+  return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_testhashs64_fnv1a(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 48);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+testhashu64Fnv1a():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 50);
+  return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_testhashu64_fnv1a(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 50);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {number} index
+ * @returns {boolean}
+ */
+testarrayofbools(index: number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 52);
+  return offset ? !!this.bb.readInt8(this.bb.__vector(this.bb_pos + offset) + index) : false;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayofboolsLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 52);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Int8Array}
+ */
+testarrayofboolsArray():Int8Array {
+  var offset = this.bb.__offset(this.bb_pos, 52);
+  return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testf():number {
+  var offset = this.bb.__offset(this.bb_pos, 54);
+  return offset ? this.bb.readFloat32(this.bb_pos + offset) : 3.14159;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testf(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 54);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testf2():number {
+  var offset = this.bb.__offset(this.bb_pos, 56);
+  return offset ? this.bb.readFloat32(this.bb_pos + offset) : 3.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testf2(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 56);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testf3():number {
+  var offset = this.bb.__offset(this.bb_pos, 58);
+  return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testf3(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 58);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {number} index
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array}
+ */
+testarrayofstring2(index: number):string
+testarrayofstring2(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array
+testarrayofstring2(index: number,optionalEncoding?:any):string|Uint8Array {
+  var offset = this.bb.__offset(this.bb_pos, 60);
+  return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayofstring2Length():number {
+  var offset = this.bb.__offset(this.bb_pos, 60);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Ability=} obj
+ * @returns {MyGame.Example.Ability}
+ */
+testarrayofsortedstruct(index: number, obj?:MyGame.Example.Ability):MyGame.Example.Ability {
+  var offset = this.bb.__offset(this.bb_pos, 62);
+  return offset ? (obj || new MyGame.Example.Ability).__init(this.bb.__vector(this.bb_pos + offset) + index * 8, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayofsortedstructLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 62);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startMonster(builder:flatbuffers.Builder) {
+  builder.startObject(30);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} posOffset
+ */
+static addPos(builder:flatbuffers.Builder, posOffset:flatbuffers.Offset) {
+  builder.addFieldStruct(0, posOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} mana
+ */
+static addMana(builder:flatbuffers.Builder, mana:number) {
+  builder.addFieldInt16(1, mana, 150);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} hp
+ */
+static addHp(builder:flatbuffers.Builder, hp:number) {
+  builder.addFieldInt16(2, hp, 100);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} nameOffset
+ */
+static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(3, nameOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} inventoryOffset
+ */
+static addInventory(builder:flatbuffers.Builder, inventoryOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(5, inventoryOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createInventoryVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+if(!data){
+  return null
+}
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startInventoryVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Color} color
+ */
+static addColor(builder:flatbuffers.Builder, color:MyGame.Example.Color) {
+  builder.addFieldInt8(6, color, MyGame.Example.Color.Blue);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Any} testType
+ */
+static addTestType(builder:flatbuffers.Builder, testType:MyGame.Example.Any) {
+  builder.addFieldInt8(7, testType, MyGame.Example.Any.NONE);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testOffset
+ */
+static addTest(builder:flatbuffers.Builder, testOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(8, testOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} test4Offset
+ */
+static addTest4(builder:flatbuffers.Builder, test4Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(9, test4Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTest4Vector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofstringOffset
+ */
+static addTestarrayofstring(builder:flatbuffers.Builder, testarrayofstringOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(10, testarrayofstringOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestarrayofstringVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+if(!data){
+  return null
+}
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addOffset(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayofstringVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayoftablesOffset
+ */
+static addTestarrayoftables(builder:flatbuffers.Builder, testarrayoftablesOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(11, testarrayoftablesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestarrayoftablesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+if(!data){
+  return null
+}
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addOffset(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayoftablesVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} enemyOffset
+ */
+static addEnemy(builder:flatbuffers.Builder, enemyOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(12, enemyOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testnestedflatbufferOffset
+ */
+static addTestnestedflatbuffer(builder:flatbuffers.Builder, testnestedflatbufferOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(13, testnestedflatbufferOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestnestedflatbufferVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+if(!data){
+  return null
+}
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestnestedflatbufferVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testemptyOffset
+ */
+static addTestempty(builder:flatbuffers.Builder, testemptyOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(14, testemptyOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {boolean} testbool
+ */
+static addTestbool(builder:flatbuffers.Builder, testbool:boolean) {
+  builder.addFieldInt8(15, +testbool, +false);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashs32Fnv1
+ */
+static addTesthashs32Fnv1(builder:flatbuffers.Builder, testhashs32Fnv1:number) {
+  builder.addFieldInt32(16, testhashs32Fnv1, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashu32Fnv1
+ */
+static addTesthashu32Fnv1(builder:flatbuffers.Builder, testhashu32Fnv1:number) {
+  builder.addFieldInt32(17, testhashu32Fnv1, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashs64Fnv1
+ */
+static addTesthashs64Fnv1(builder:flatbuffers.Builder, testhashs64Fnv1:flatbuffers.Long) {
+  builder.addFieldInt64(18, testhashs64Fnv1, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashu64Fnv1
+ */
+static addTesthashu64Fnv1(builder:flatbuffers.Builder, testhashu64Fnv1:flatbuffers.Long) {
+  builder.addFieldInt64(19, testhashu64Fnv1, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashs32Fnv1a
+ */
+static addTesthashs32Fnv1a(builder:flatbuffers.Builder, testhashs32Fnv1a:number) {
+  builder.addFieldInt32(20, testhashs32Fnv1a, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashu32Fnv1a
+ */
+static addTesthashu32Fnv1a(builder:flatbuffers.Builder, testhashu32Fnv1a:number) {
+  builder.addFieldInt32(21, testhashu32Fnv1a, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashs64Fnv1a
+ */
+static addTesthashs64Fnv1a(builder:flatbuffers.Builder, testhashs64Fnv1a:flatbuffers.Long) {
+  builder.addFieldInt64(22, testhashs64Fnv1a, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashu64Fnv1a
+ */
+static addTesthashu64Fnv1a(builder:flatbuffers.Builder, testhashu64Fnv1a:flatbuffers.Long) {
+  builder.addFieldInt64(23, testhashu64Fnv1a, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofboolsOffset
+ */
+static addTestarrayofbools(builder:flatbuffers.Builder, testarrayofboolsOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(24, testarrayofboolsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<boolean>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestarrayofboolsVector(builder:flatbuffers.Builder, data:boolean[]):flatbuffers.Offset {
+if(!data){
+  return null
+}
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(+data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayofboolsVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testf
+ */
+static addTestf(builder:flatbuffers.Builder, testf:number) {
+  builder.addFieldFloat32(25, testf, 3.14159);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testf2
+ */
+static addTestf2(builder:flatbuffers.Builder, testf2:number) {
+  builder.addFieldFloat32(26, testf2, 3.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testf3
+ */
+static addTestf3(builder:flatbuffers.Builder, testf3:number) {
+  builder.addFieldFloat32(27, testf3, 0.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofstring2Offset
+ */
+static addTestarrayofstring2(builder:flatbuffers.Builder, testarrayofstring2Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(28, testarrayofstring2Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestarrayofstring2Vector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+if(!data){
+  return null
+}
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addOffset(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayofstring2Vector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofsortedstructOffset
+ */
+static addTestarrayofsortedstruct(builder:flatbuffers.Builder, testarrayofsortedstructOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(29, testarrayofsortedstructOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayofsortedstructVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(8, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endMonster(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  builder.requiredField(offset, 10); // name
+  return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} offset
+ */
+static finishMonsterBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
+  builder.finish(offset, 'MONS');
+};
+
+}
+}
diff --git a/tests/namespace_test/namespace_test1_generated.ts b/tests/namespace_test/namespace_test1_generated.ts
new file mode 100644
index 00000000..f94d14a5
--- /dev/null
+++ b/tests/namespace_test/namespace_test1_generated.ts
@@ -0,0 +1,180 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import { flatbuffers } from "./flatbuffers"
+/**
+ * @enum
+ */
+export namespace NamespaceA.NamespaceB{
+export enum EnumInNestedNS{
+  A= 0,
+  B= 1,
+  C= 2
+}};
+
+/**
+ * @constructor
+ */
+export namespace NamespaceA.NamespaceB{
+export class TableInNestedNS {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {TableInNestedNS}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TableInNestedNS {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {TableInNestedNS=} obj
+ * @returns {TableInNestedNS}
+ */
+static getRootAsTableInNestedNS(bb:flatbuffers.ByteBuffer, obj?:TableInNestedNS):TableInNestedNS {
+  return (obj || new TableInNestedNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+foo():number {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_foo(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startTableInNestedNS(builder:flatbuffers.Builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} foo
+ */
+static addFoo(builder:flatbuffers.Builder, foo:number) {
+  builder.addFieldInt32(0, foo, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endTableInNestedNS(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace NamespaceA.NamespaceB{
+export class StructInNestedNS {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {StructInNestedNS}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):StructInNestedNS {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+a():number {
+  return this.bb.readInt32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_a(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+b():number {
+  return this.bb.readInt32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_b(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} a
+ * @param {number} b
+ * @returns {flatbuffers.Offset}
+ */
+static createStructInNestedNS(builder:flatbuffers.Builder, a: number, b: number):flatbuffers.Offset {
+  builder.prep(4, 8);
+  builder.writeInt32(b);
+  builder.writeInt32(a);
+  return builder.offset();
+};
+
+}
+}
diff --git a/tests/namespace_test/namespace_test2_generated.ts b/tests/namespace_test/namespace_test2_generated.ts
new file mode 100644
index 00000000..babf8adc
--- /dev/null
+++ b/tests/namespace_test/namespace_test2_generated.ts
@@ -0,0 +1,277 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import { flatbuffers } from "./flatbuffers"
+import * as NS9459827973991502386 from "./namespace_test1_generated";
+export * from "./namespace_test1_generated";
+/**
+ * @constructor
+ */
+export namespace NamespaceA{
+export class TableInFirstNS {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {TableInFirstNS}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TableInFirstNS {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {TableInFirstNS=} obj
+ * @returns {TableInFirstNS}
+ */
+static getRootAsTableInFirstNS(bb:flatbuffers.ByteBuffer, obj?:TableInFirstNS):TableInFirstNS {
+  return (obj || new TableInFirstNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceA.NamespaceB.TableInNestedNS=} obj
+ * @returns {NamespaceA.NamespaceB.TableInNestedNS}
+ */
+fooTable(obj?:NS9459827973991502386.NamespaceA.NamespaceB.TableInNestedNS):NS9459827973991502386.NamespaceA.NamespaceB.TableInNestedNS {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? (obj || new NS9459827973991502386.NamespaceA.NamespaceB.TableInNestedNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @returns {NamespaceA.NamespaceB.EnumInNestedNS}
+ */
+fooEnum():NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? /** @type {NamespaceA.NamespaceB.EnumInNestedNS} */ (this.bb.readInt8(this.bb_pos + offset)) : NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS.A;
+};
+
+/**
+ * @param {NamespaceA.NamespaceB.EnumInNestedNS} value
+ * @returns {boolean}
+ */
+mutate_foo_enum(value:NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {NamespaceA.NamespaceB.StructInNestedNS=} obj
+ * @returns {NamespaceA.NamespaceB.StructInNestedNS}
+ */
+fooStruct(obj?:NS9459827973991502386.NamespaceA.NamespaceB.StructInNestedNS):NS9459827973991502386.NamespaceA.NamespaceB.StructInNestedNS {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? (obj || new NS9459827973991502386.NamespaceA.NamespaceB.StructInNestedNS).__init(this.bb_pos + offset, this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startTableInFirstNS(builder:flatbuffers.Builder) {
+  builder.startObject(3);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} fooTableOffset
+ */
+static addFooTable(builder:flatbuffers.Builder, fooTableOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, fooTableOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {NamespaceA.NamespaceB.EnumInNestedNS} fooEnum
+ */
+static addFooEnum(builder:flatbuffers.Builder, fooEnum:NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS) {
+  builder.addFieldInt8(1, fooEnum, NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS.A);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} fooStructOffset
+ */
+static addFooStruct(builder:flatbuffers.Builder, fooStructOffset:flatbuffers.Offset) {
+  builder.addFieldStruct(2, fooStructOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endTableInFirstNS(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace NamespaceC{
+export class TableInC {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {TableInC}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TableInC {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {TableInC=} obj
+ * @returns {TableInC}
+ */
+static getRootAsTableInC(bb:flatbuffers.ByteBuffer, obj?:TableInC):TableInC {
+  return (obj || new TableInC).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceA.TableInFirstNS=} obj
+ * @returns {NamespaceA.TableInFirstNS}
+ */
+referToA1(obj?:NamespaceA.TableInFirstNS):NamespaceA.TableInFirstNS {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? (obj || new NamespaceA.TableInFirstNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {NamespaceA.SecondTableInA=} obj
+ * @returns {NamespaceA.SecondTableInA}
+ */
+referToA2(obj?:NamespaceA.SecondTableInA):NamespaceA.SecondTableInA {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? (obj || new NamespaceA.SecondTableInA).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startTableInC(builder:flatbuffers.Builder) {
+  builder.startObject(2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToA1Offset
+ */
+static addReferToA1(builder:flatbuffers.Builder, referToA1Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, referToA1Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToA2Offset
+ */
+static addReferToA2(builder:flatbuffers.Builder, referToA2Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(1, referToA2Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endTableInC(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace NamespaceA{
+export class SecondTableInA {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer= null;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {SecondTableInA}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):SecondTableInA {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {SecondTableInA=} obj
+ * @returns {SecondTableInA}
+ */
+static getRootAsSecondTableInA(bb:flatbuffers.ByteBuffer, obj?:SecondTableInA):SecondTableInA {
+  return (obj || new SecondTableInA).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceC.TableInC=} obj
+ * @returns {NamespaceC.TableInC}
+ */
+referToC(obj?:NamespaceC.TableInC):NamespaceC.TableInC {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? (obj || new NamespaceC.TableInC).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startSecondTableInA(builder:flatbuffers.Builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToCOffset
+ */
+static addReferToC(builder:flatbuffers.Builder, referToCOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, referToCOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endSecondTableInA(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
-- 
GitLab