IGNITE-11032 Move to TypeScript

This closes #1
diff --git a/.gitignore b/.gitignore
index 58ca0e8..8a76192 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@
 build
 npm-debug.log
 /logs
-package-lock.json
\ No newline at end of file
+package-lock.json
+dist
\ No newline at end of file
diff --git a/examples/AuthTlsExample.js b/examples/AuthTlsExample.js
index b47df61..7fb989d 100644
--- a/examples/AuthTlsExample.js
+++ b/examples/AuthTlsExample.js
@@ -16,13 +16,7 @@
  */
 
 const FS = require('fs');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
-const BinaryObject = IgniteClient.BinaryObject;
-const CacheEntry = IgniteClient.CacheEntry;
-const ScanQuery = IgniteClient.ScanQuery;
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
+const {IgniteClient, ObjectType, ComplexObjectType, BinaryObject, CacheEntry, ScanQuery, IgniteClientConfiguration} = require('apache-ignite-client');
 
 const ENDPOINT = 'localhost:10800';
 const USER_NAME = 'ignite';
diff --git a/examples/CachePutGetExample.js b/examples/CachePutGetExample.js
index b37f573..bc563f8 100644
--- a/examples/CachePutGetExample.js
+++ b/examples/CachePutGetExample.js
@@ -15,13 +15,7 @@
  * limitations under the License.
  */
 
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
-const BinaryObject = IgniteClient.BinaryObject;
-const CacheEntry = IgniteClient.CacheEntry;
-const ScanQuery = IgniteClient.ScanQuery;
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
+const {IgniteClient, ObjectType, ComplexObjectType, BinaryObject, CacheEntry, ScanQuery, IgniteClientConfiguration} = require('apache-ignite-client');
 
 const ENDPOINT = '127.0.0.1:10800';
 
diff --git a/examples/FailoverExample.js b/examples/FailoverExample.js
index 25db544..a024cdf 100644
--- a/examples/FailoverExample.js
+++ b/examples/FailoverExample.js
@@ -15,8 +15,7 @@
  * limitations under the License.
  */
 
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
+const {IgniteClient, IgniteClientConfiguration} = require('apache-ignite-client');
 
 const ENDPOINT1 = 'localhost:10800';
 const ENDPOINT2 = 'localhost:10801';
@@ -33,7 +32,7 @@
     try {
         const igniteClientConfiguration = new IgniteClientConfiguration(
             ENDPOINT1, ENDPOINT2, ENDPOINT3);
-        // connect to Ignite a node
+        // connect to an Ignite node
         await igniteClient.connect(igniteClientConfiguration);
     }
     catch (err) {
diff --git a/examples/SqlExample.js b/examples/SqlExample.js
index 92f59d7..c9a3af9 100644
--- a/examples/SqlExample.js
+++ b/examples/SqlExample.js
@@ -16,12 +16,7 @@
  */
 
 const Util = require('util');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
-const SqlFieldsQuery = IgniteClient.SqlFieldsQuery;
-const SqlQuery = IgniteClient.SqlQuery;
+const {IgniteClient, ObjectType, CacheConfiguration, SqlFieldsQuery, SqlQuery, IgniteClientConfiguration} = require('apache-ignite-client');
 
 const ENDPOINT = '127.0.0.1:10800';
 
diff --git a/examples/SqlQueryEntriesExample.js b/examples/SqlQueryEntriesExample.js
index ecbcbd5..14b13d4 100644
--- a/examples/SqlQueryEntriesExample.js
+++ b/examples/SqlQueryEntriesExample.js
@@ -16,15 +16,7 @@
  */
 
 const Util = require('util');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
-const QueryEntity = IgniteClient.QueryEntity;
-const QueryField = IgniteClient.QueryField;
-const SqlFieldsQuery = IgniteClient.SqlFieldsQuery;
-const SqlQuery = IgniteClient.SqlQuery;
+const {IgniteClient, ObjectType, CacheConfiguration, SqlFieldsQuery, SqlQuery, IgniteClientConfiguration,ComplexObjectType,QueryEntity,QueryField} = require('apache-ignite-client');
 
 const ENDPOINT = '127.0.0.1:10800';
 
diff --git a/index.js b/index.js
deleted file mode 100644
index cce86ab..0000000
--- a/index.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-'use strict';
-
-module.exports = require('./lib/IgniteClient');
-module.exports.ObjectType = require('./lib/ObjectType').ObjectType;
-module.exports.MapObjectType = require('./lib/ObjectType').MapObjectType;
-module.exports.CollectionObjectType = require('./lib/ObjectType').CollectionObjectType;
-module.exports.ComplexObjectType = require('./lib/ObjectType').ComplexObjectType;
-module.exports.ObjectArrayType = require('./lib/ObjectType').ObjectArrayType;
-module.exports.BinaryObject = require('./lib/BinaryObject');
-module.exports.Timestamp = require('./lib/Timestamp');
-module.exports.EnumItem = require('./lib/EnumItem');
-module.exports.Decimal = require('decimal.js');
-module.exports.Errors = require('./lib/Errors');
-module.exports.IgniteClientConfiguration = require('./lib/IgniteClientConfiguration');
-module.exports.CacheClient = require('./lib/CacheClient');
-module.exports.CacheEntry = require('./lib/CacheClient').CacheEntry;
-module.exports.CacheConfiguration = require('./lib/CacheConfiguration');
-module.exports.QueryEntity = require('./lib/CacheConfiguration').QueryEntity;
-module.exports.QueryField = require('./lib/CacheConfiguration').QueryField;
-module.exports.QueryIndex = require('./lib/CacheConfiguration').QueryIndex;
-module.exports.CacheKeyConfiguration = require('./lib/CacheConfiguration').CacheKeyConfiguration;
-module.exports.SqlQuery = require('./lib/Query').SqlQuery;
-module.exports.SqlFieldsQuery = require('./lib/Query').SqlFieldsQuery;
-module.exports.ScanQuery = require('./lib/Query').ScanQuery;
-module.exports.Cursor = require('./lib/Cursor').Cursor;
-module.exports.SqlFieldsCursor = require('./lib/Cursor').SqlFieldsCursor;
diff --git a/package.json b/package.json
index 6497f67..57082ea 100644
--- a/package.json
+++ b/package.json
@@ -2,11 +2,11 @@
   "name": "apache-ignite-client",
   "version": "1.1.0",
   "description": "NodeJS Client for Apache Ignite",
-  "main": "index.js",
+  "main": "./dist/index.js",
+  "types": "./dist/index.d.ts",
   "files": [
-    "/examples",
-    "/lib",
-    "index.js"
+    "dist",
+    "examples"
   ],
   "repository": {
     "type": "git",
@@ -23,22 +23,27 @@
     "node": ">=8.0.0"
   },
   "dependencies": {
-    "long": "latest",
-    "decimal.js": "latest"
+    "decimal.js": "10.2.1",
+    "long": "4.0.0"
   },
   "scripts": {
     "test": "jasmine",
     "test:examples": "node ./spec/ExamplesExecutor.js Examples",
     "test:auth_example": "node ./spec/ExamplesExecutor.js AuthExample",
-    "test:affinity_awareness": "APACHE_IGNITE_CLIENT_AFFINITY_AWARENESS=true node ./spec/PartitionAwarenessExecutor.js",
-    "test:partition_awareness": "APACHE_IGNITE_CLIENT_AFFINITY_AWARENESS=true node ./spec/PartitionAwarenessExecutor.js"
+    "test:partition_awareness": "APACHE_IGNITE_CLIENT_PARTITION_AWARENESS=true node ./spec/PartitionAwarenessExecutor.js",
+    "build": "tsc"
   },
   "devDependencies": {
-    "jasmine": "3.6.1",
-    "jasmine-expect": "4.0.0",
-    "jasmine-reporters": "2.1.1",
-    "ps-tree": "latest",
-    "process-exists": "latest",
-    "glob": "7.1.6"
+    "jasmine": "3.6.2",
+    "jasmine-expect": "5.0.0",
+    "jasmine-reporters": "2.3.2",
+    "ps-tree": "1.2.0",
+    "process-exists": "4.0.0",
+    "glob": "7.1.6",
+    "@types/node": "14.14.2",
+    "@types/long": "4.0.1",
+    "typescript": "4.0.3",
+    "source-map-support": "^0.5.19",
+    "ts-node": "9.0.0"
   }
 }
diff --git a/spec/PartitionAwarenessExecutor.js b/spec/PartitionAwarenessExecutor.js
index f546d43..7e6004d 100644
--- a/spec/PartitionAwarenessExecutor.js
+++ b/spec/PartitionAwarenessExecutor.js
@@ -29,5 +29,4 @@
     // If this is set to true, we won't clean up environment, i.e. stop nodes
     "stopOnSpecFailure": false
 });
-// We exclude the "scan query test suite > scan query settings" spec because sometimes it fails with more than one node cluster
-jasmine.execute(null, "(?!^scan query test suite > scan query settings$)(^.*$)");
\ No newline at end of file
+jasmine.execute();
diff --git a/spec/TestingHelper.js b/spec/TestingHelper.js
index fee97bc..83b2c8c 100644
--- a/spec/TestingHelper.js
+++ b/spec/TestingHelper.js
@@ -26,15 +26,8 @@
 const fs = require('fs');
 const child_process = require('child_process');
 const config = require('./config');
-const IgniteClient = require('apache-ignite-client');
 const LogReader = require('./LogReader');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const Errors = IgniteClient.Errors;
-const EnumItem = IgniteClient.EnumItem;
-const Timestamp = IgniteClient.Timestamp;
-const Decimal = IgniteClient.Decimal;
-const BinaryObject = IgniteClient.BinaryObject;
-const ObjectType = IgniteClient.ObjectType;
+const {IgniteClient, IgniteClientConfiguration, Errors, EnumItem, Timestamp, Decimal, BinaryObject, ObjectType} = require('apache-ignite-client');
 
 const TIMEOUT_MS = 60000;
 
@@ -262,7 +255,8 @@
 
     static getNodeRunner() {
         if (!config.igniteHome)
-            throw 'Can not start node: IGNITE_HOME is not set';
+            throw 'Can not start node: ' +
+            'IGNITE_HOME is not set';
 
         const ext = TestingHelper.isWindows() ? '.bat' : '.sh';
         const runner = path.join(config.igniteHome, 'bin', 'ignite' + ext);
@@ -529,7 +523,7 @@
             throw 'Failed to start Node: timeout while trying to connect';
         }
 
-        return srv
+        return srv;
     }
 
     static executeExample(name, outputChecker) {
diff --git a/spec/cache/BinaryObject.spec.js b/spec/cache/BinaryObject.spec.js
index 0442510..85e70ef 100644
--- a/spec/cache/BinaryObject.spec.js
+++ b/spec/cache/BinaryObject.spec.js
@@ -21,11 +21,7 @@
 
 const Util = require('util');
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
-const MapObjectType = IgniteClient.MapObjectType;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
-const BinaryObject = IgniteClient.BinaryObject;
+const {IgniteClient, ObjectType, MapObjectType, ComplexObjectType, BinaryObject} = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 
diff --git a/spec/cache/Cache.spec.js b/spec/cache/Cache.spec.js
index 713294b..2fb03b5 100644
--- a/spec/cache/Cache.spec.js
+++ b/spec/cache/Cache.spec.js
@@ -21,12 +21,7 @@
 
 const config = require('../config');
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const Errors = IgniteClient.Errors;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
-const QueryEntity = IgniteClient.QueryEntity;
-const QueryField = IgniteClient.QueryField;
-const QueryIndex = IgniteClient.QueryIndex;
+const {IgniteClient, Errors, CacheConfiguration, QueryEntity, QueryField, QueryIndex} = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const CACHE_NAME2 = '__test_cache2';
diff --git a/spec/cache/CacheKeyValueOps.spec.js b/spec/cache/CacheKeyValueOps.spec.js
index d34276c..fa7020c 100644
--- a/spec/cache/CacheKeyValueOps.spec.js
+++ b/spec/cache/CacheKeyValueOps.spec.js
@@ -20,11 +20,7 @@
 require('jasmine-expect');
 
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
-const CacheClient = IgniteClient.CacheClient;
-const CacheEntry = IgniteClient.CacheEntry;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
+const {IgniteClient, ObjectType, CacheConfiguration, CacheClient, CacheEntry} = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 
diff --git a/spec/cache/CachePutGetDiffTypes.spec.js b/spec/cache/CachePutGetDiffTypes.spec.js
index 5fd370e..619735a 100644
--- a/spec/cache/CachePutGetDiffTypes.spec.js
+++ b/spec/cache/CachePutGetDiffTypes.spec.js
@@ -20,16 +20,7 @@
 require('jasmine-expect');
 
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
-const MapObjectType = IgniteClient.MapObjectType;
-const CollectionObjectType = IgniteClient.CollectionObjectType;
-const ObjectArrayType = IgniteClient.ObjectArrayType;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
-const EnumItem = IgniteClient.EnumItem;
-const Timestamp = IgniteClient.Timestamp;
-const Decimal = IgniteClient.Decimal;
-const BinaryObject = IgniteClient.BinaryObject;
+const {IgniteClient, ObjectType, MapObjectType, ComplexObjectType, CollectionObjectType, BinaryObject, ObjectArrayType, EnumItem, Timestamp, Decimal} = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 
diff --git a/spec/cache/ComplexObject.spec.js b/spec/cache/ComplexObject.spec.js
index 9cc8115..160c930 100644
--- a/spec/cache/ComplexObject.spec.js
+++ b/spec/cache/ComplexObject.spec.js
@@ -21,11 +21,7 @@
 
 const Util = require('util');
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
-const MapObjectType = IgniteClient.MapObjectType;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
-const BinaryObject = IgniteClient.BinaryObject;
+const { IgniteClient, ObjectType, MapObjectType, ComplexObjectType, BinaryObject } = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const ONE_BYTE_MAX_OFFSET = 0x100 - 1;
diff --git a/spec/cache/UUID.spec.js b/spec/cache/UUID.spec.js
index 1715113..e036fec 100644
--- a/spec/cache/UUID.spec.js
+++ b/spec/cache/UUID.spec.js
@@ -20,10 +20,7 @@
 require('jasmine-expect');
 
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const CacheConfiguration = IgniteClient.CacheConfiguration;
-const SqlFieldsQuery = IgniteClient.SqlFieldsQuery;
-const ObjectType = IgniteClient.ObjectType;
+const { IgniteClient, CacheConfiguration, SqlFieldsQuery, ObjectType } = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const TABLE_NAME = '__test_UUID_table';
diff --git a/spec/config.js b/spec/config.js
index d8966a8..1a7e7a0 100644
--- a/spec/config.js
+++ b/spec/config.js
@@ -18,9 +18,9 @@
 'use strict';
 
 exports.endpoints = process.env.APACHE_IGNITE_CLIENT_ENDPOINTS ?
-    process.env.APACHE_IGNITE_CLIENT_ENDPOINTS.split(',') : [];
+                    process.env.APACHE_IGNITE_CLIENT_ENDPOINTS.split(',') : [];
 exports.debug = process.env.APACHE_IGNITE_CLIENT_DEBUG === 'true' ||
-    process.env.APACHE_IGNITE_CLIENT_DEBUG === '1';
+                process.env.APACHE_IGNITE_CLIENT_DEBUG === '1';
 exports.nodeDebug = process.env.APACHE_IGNITE_SERVER_DEBUG === 'true' ||
     process.env.APACHE_IGNITE_SERVER_DEBUG === '1';
 exports.partitionAwareness = process.env.APACHE_IGNITE_CLIENT_PARTITION_AWARENESS === 'true' ||
diff --git a/spec/partition_awareness/PartitionAwarenessConnection.spec.js b/spec/partition_awareness/PartitionAwarenessConnection.spec.js
index 6f1ee92..0e37cfc 100644
--- a/spec/partition_awareness/PartitionAwarenessConnection.spec.js
+++ b/spec/partition_awareness/PartitionAwarenessConnection.spec.js
@@ -21,9 +21,7 @@
 
 const TestingHelper = require('../TestingHelper');
 const PartitionAwarenessTestUtils = require('./PartitionAwarenessTestUtils');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
+const { IgniteClientConfiguration, ObjectType} = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const SERVER_NUM = 3;
diff --git a/spec/partition_awareness/PartitionAwarenessFailover.spec.js b/spec/partition_awareness/PartitionAwarenessFailover.spec.js
index 923a84d..4d2cbbf 100644
--- a/spec/partition_awareness/PartitionAwarenessFailover.spec.js
+++ b/spec/partition_awareness/PartitionAwarenessFailover.spec.js
@@ -21,8 +21,7 @@
 
 const TestingHelper = require('../TestingHelper');
 const PartitionAwarenessTestUtils = require('./PartitionAwarenessTestUtils');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
+const { ObjectType } = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const SERVER_NUM = 3;
diff --git a/spec/partition_awareness/PartitionAwarenessLocalPeek.spec.js b/spec/partition_awareness/PartitionAwarenessLocalPeek.spec.js
index 4157afd..b4b67f0 100644
--- a/spec/partition_awareness/PartitionAwarenessLocalPeek.spec.js
+++ b/spec/partition_awareness/PartitionAwarenessLocalPeek.spec.js
@@ -14,19 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 'use strict';
 
 require('jasmine-expect');
 
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const Errors = IgniteClient.Errors;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
-const CacheKeyConfiguration = IgniteClient.CacheKeyConfiguration;
-const ObjectType = IgniteClient.ObjectType;
-const BinaryObject = IgniteClient.BinaryObject;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
+const { IgniteClient, CacheConfiguration, CacheKeyConfiguration, ObjectType, BinaryObject, ComplexObjectType } = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 
diff --git a/spec/partition_awareness/PartitionAwarenessMultipleConnections.spec.js b/spec/partition_awareness/PartitionAwarenessMultipleConnections.spec.js
index cfba699..d2bd0b7 100644
--- a/spec/partition_awareness/PartitionAwarenessMultipleConnections.spec.js
+++ b/spec/partition_awareness/PartitionAwarenessMultipleConnections.spec.js
@@ -21,8 +21,7 @@
 
 const TestingHelper = require('../TestingHelper');
 const PartitionAwarenessTestUtils = require('./PartitionAwarenessTestUtils');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
+const { ObjectType } = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const CUSTOM_AFFINITY_CACHE = 'custom-affinity';
diff --git a/spec/partition_awareness/PartitionAwarenessSingleServer.spec.js b/spec/partition_awareness/PartitionAwarenessSingleServer.spec.js
index 7c72fca..82e9538 100644
--- a/spec/partition_awareness/PartitionAwarenessSingleServer.spec.js
+++ b/spec/partition_awareness/PartitionAwarenessSingleServer.spec.js
@@ -21,8 +21,7 @@
 
 const TestingHelper = require('../TestingHelper');
 const PartitionAwarenessTestUtils = require('./PartitionAwarenessTestUtils');
-const IgniteClient = require('apache-ignite-client');
-const ObjectType = IgniteClient.ObjectType;
+const { ObjectType } = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const SERVER_NUM = 3;
diff --git a/spec/partition_awareness/PartitionAwarenessTestUtils.js b/spec/partition_awareness/PartitionAwarenessTestUtils.js
index 2e2ef1a..9386695 100644
--- a/spec/partition_awareness/PartitionAwarenessTestUtils.js
+++ b/spec/partition_awareness/PartitionAwarenessTestUtils.js
@@ -20,8 +20,7 @@
 require('jasmine-expect');
 
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const CacheConfiguration = IgniteClient.CacheConfiguration;
+const {IgniteClient, CacheConfiguration} = require('apache-ignite-client');
 
 // Helper class for testing partition awareness feature of apache-ignite-client library.
 class PartitionAwarenessTestUtils {
diff --git a/spec/query/ScanQuery.spec.js b/spec/query/ScanQuery.spec.js
index ab28973..2d29bbb 100644
--- a/spec/query/ScanQuery.spec.js
+++ b/spec/query/ScanQuery.spec.js
@@ -21,10 +21,7 @@
 
 const config = require('../config');
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const Errors = IgniteClient.Errors;
-const ScanQuery = IgniteClient.ScanQuery;
-const ObjectType = IgniteClient.ObjectType;
+const {IgniteClient, Errors, ScanQuery, ObjectType} = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const ELEMENTS_NUMBER = 10;
diff --git a/spec/query/SqlFieldsQuery.spec.js b/spec/query/SqlFieldsQuery.spec.js
index bf75759..01760c2 100644
--- a/spec/query/SqlFieldsQuery.spec.js
+++ b/spec/query/SqlFieldsQuery.spec.js
@@ -21,11 +21,7 @@
 
 const config = require('../config');
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const Errors = IgniteClient.Errors;
-const SqlFieldsQuery = IgniteClient.SqlFieldsQuery;
-const ObjectType = IgniteClient.ObjectType;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
+const {IgniteClient, Errors, SqlFieldsQuery, ObjectType, CacheConfiguration} = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const TABLE_NAME = '__test_SqlFieldsQuery_table';
diff --git a/spec/query/SqlQuery.spec.js b/spec/query/SqlQuery.spec.js
index c2e2bb1..1ffd2ad 100644
--- a/spec/query/SqlQuery.spec.js
+++ b/spec/query/SqlQuery.spec.js
@@ -21,15 +21,7 @@
 
 const config = require('../config');
 const TestingHelper = require('../TestingHelper');
-const IgniteClient = require('apache-ignite-client');
-const Errors = IgniteClient.Errors;
-const SqlQuery = IgniteClient.SqlQuery;
-const SqlFieldsQuery = IgniteClient.SqlFieldsQuery;
-const ObjectType = IgniteClient.ObjectType;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
-const QueryEntity = IgniteClient.QueryEntity;
-const QueryField = IgniteClient.QueryField;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
+const {IgniteClient, Errors, SqlQuery, SqlFieldsQuery, ObjectType, CacheConfiguration, QueryEntity, QueryField, ComplexObjectType} = require('apache-ignite-client');
 
 const CACHE_NAME = '__test_cache';
 const TABLE_NAME = '__test_SqlQuery';
diff --git a/lib/BinaryObject.js b/src/BinaryObject.ts
similarity index 87%
rename from lib/BinaryObject.js
rename to src/BinaryObject.ts
index b7da8d6..d799486 100644
--- a/lib/BinaryObject.js
+++ b/src/BinaryObject.ts
@@ -17,17 +17,16 @@
 
 'use strict';
 
-const Util = require('util');
-const ObjectType = require('./ObjectType').ObjectType;
-const ComplexObjectType = require('./ObjectType').ComplexObjectType;
-const Errors = require('./Errors');
-const BinaryUtils = require('./internal/BinaryUtils');
-const BinaryType = require('./internal/BinaryType');
-const BinaryField = require('./internal/BinaryType').BinaryField;
-const BinaryTypeBuilder = require('./internal/BinaryType').BinaryTypeBuilder;
-const ArgumentChecker = require('./internal/ArgumentChecker');
-const MessageBuffer = require('./internal/MessageBuffer');
-const Logger = require('./internal/Logger');
+import * as Util from "util";
+import {ComplexObjectType, CompositeType, ObjectType} from "./ObjectType";
+import BinaryUtils from "./internal/BinaryUtils";
+import BinaryType, {BinaryField, BinaryTypeBuilder} from "./internal/BinaryType";
+import ArgumentChecker from "./internal/ArgumentChecker";
+import MessageBuffer from "./internal/MessageBuffer";
+import Logger from "./internal/Logger";
+import { IgniteClientError } from "./Errors";
+import { PRIMITIVE_TYPE } from "./internal/Constants";
+import BinaryCommunicator from "./internal/BinaryCommunicator";
 
 const HEADER_LENGTH = 24;
 const VERSION = 1;
@@ -58,7 +57,19 @@
  *   - created using the public constructor. Fields may be added to such an instance using setField() method.
  *   - created from a JavaScript object using static fromObject() method.
  */
-class BinaryObject {
+export class BinaryObject {
+    private _typeBuilder: BinaryTypeBuilder;
+    private _modified: boolean;
+    private _hasSchema: boolean;
+    private _compactFooter: boolean;
+    private _hasRawData: boolean;
+    private _fields: Map<number, BinaryObjectField>;
+    private _buffer: MessageBuffer;
+    private _startPos: number;
+    private _hashCode: number;
+    private _schemaOffset: number;
+    private _length: number;
+    private _offsetType: PRIMITIVE_TYPE;
 
     /**
      * Creates an instance of the BinaryObject without any fields.
@@ -71,10 +82,10 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    constructor(typeName) {
+    constructor(typeName: string) {
         ArgumentChecker.notEmpty(typeName, 'typeName');
         this._buffer = null;
-        this._fields = new Map();
+        this._fields = new Map<number, BinaryObjectField>();
         this._typeBuilder = BinaryTypeBuilder.fromTypeName(typeName);
         this._modified = false;
         this._schemaOffset = null;
@@ -121,7 +132,7 @@
                     complexObjectType ? complexObjectType._getFieldType(fieldName) : null);
             }
             else {
-                throw Errors.IgniteClientError.serializationError(
+                throw IgniteClientError.serializationError(
                     true, Util.format('field "%s" is undefined', fieldName));
             }
         }
@@ -236,7 +247,7 @@
         for (let field of this._fields.values()) {
             binaryField = this._typeBuilder.getField(field.id);
             if (!binaryField) {
-                throw Errors.IgniteClientError.serializationError(
+                throw IgniteClientError.serializationError(
                     false, Util.format('field with id "%s" can not be deserialized', field.id));
             }
             fieldName = binaryField.name;
@@ -254,6 +265,10 @@
         return this._typeBuilder.getTypeName();
     }
 
+    get fields() {
+        return this._fields;
+    }
+
     /**
      * Returns names of all fields of this BinaryObject instance.
      *
@@ -262,13 +277,13 @@
      * @throws {IgniteClientError} if error.
      */
     getFieldNames() {
-        return this._typeBuilder._schema.fieldIds.map(fieldId => {
+        return this._typeBuilder.schema.fieldIds.map(fieldId => {
             const field = this._typeBuilder.getField(fieldId);
             if (field) {
                 return field.name;
             }
             else {
-                throw Errors.IgniteClientError.internalError(
+                throw IgniteClientError.internalError(
                     Util.format('Field "%s" is absent in binary type fields', fieldId));
             }
         });
@@ -286,8 +301,8 @@
     /**
      * @ignore
      */
-    static async _fromBuffer(communicator, buffer) {
-        const result = new BinaryObject(new ComplexObjectType({})._typeName);
+    static async _fromBuffer(communicator: BinaryCommunicator, buffer: MessageBuffer) {
+        const result = new BinaryObject(new ComplexObjectType({}).typeName);
         result._buffer = buffer;
         result._startPos = buffer.position;
         await result._read(communicator);
@@ -297,7 +312,7 @@
     /**
      * @ignore
      */
-    async _getHashCode(communicator) {
+    async _getHashCode(communicator: BinaryCommunicator) {
         if (this._hashCode !== null && !this._modified) {
             return this._hashCode;
         }
@@ -396,8 +411,8 @@
         await this._readHeader(communicator);
         if (this._hasSchema) {
             this._buffer.position = this._startPos + this._schemaOffset;
-            const fieldOffsets = new Array();
-            const fieldIds = this._typeBuilder._schema.fieldIds;
+            const fieldOffsets = [];
+            const fieldIds = this._typeBuilder.schema.fieldIds;
             let index = 0;
             let fieldId;
             let schemaEndOffset = this._startPos + this._length;
@@ -407,11 +422,11 @@
             while (this._buffer.position < schemaEndOffset) {
                 if (!this._compactFooter) {
                     fieldId = this._buffer.readInteger();
-                    this._typeBuilder._schema.addField(fieldId);
+                    this._typeBuilder.schema.addField(fieldId);
                 }
                 else {
                     if (index >= fieldIds.length) {
-                        throw Errors.IgniteClientError.serializationError(
+                        throw IgniteClientError.serializationError(
                             false, 'wrong number of fields in schema');
                     }
                     fieldId = fieldIds[index];
@@ -444,7 +459,7 @@
         // version
         const version = this._buffer.readByte();
         if (version !== VERSION) {
-            throw Errors.IgniteClientError.internalError();
+            throw IgniteClientError.internalError();
         }
         // flags
         const flags = this._buffer.readShort();
@@ -473,8 +488,27 @@
 /**
  * @ignore
  */
-class BinaryObjectField {
-    constructor(name, value = undefined, type = null) {
+export class BinaryObjectField {
+
+    private _name: string;
+
+    private _id: number;
+
+    private _value: object;
+
+    private _type: PRIMITIVE_TYPE | CompositeType;
+
+    private _typeCode: number;
+
+    private _communicator: BinaryCommunicator;
+
+    private _buffer: MessageBuffer;
+
+    private _offset: number;
+
+    private _length: number;
+
+    constructor(name: string, value = undefined, type = null) {
         this._name = name;
         this._id = BinaryField._calculateId(name);
         this._value = value;
@@ -516,7 +550,7 @@
         return BinaryUtils.TYPE_CODE.INTEGER;
     }
 
-    static _fromBuffer(communicator, buffer, offset, length, id) {
+    static _fromBuffer(communicator: BinaryCommunicator, buffer: MessageBuffer, offset: number, length: number, id: number) {
         const result = new BinaryObjectField(null);
         result._id = id;
         result._communicator = communicator;
@@ -548,5 +582,3 @@
         buffer.writeNumber(this._offset - headerStartPos, offsetType, false);
     }
 }
-
-module.exports = BinaryObject;
diff --git a/lib/CacheClient.js b/src/CacheClient.ts
similarity index 92%
rename from lib/CacheClient.js
rename to src/CacheClient.ts
index 597cda0..40cbe00 100644
--- a/lib/CacheClient.js
+++ b/src/CacheClient.ts
@@ -17,11 +17,13 @@
 
 'use strict';
 
-const BinaryUtils = require('./internal/BinaryUtils');
-const ArgumentChecker = require('./internal/ArgumentChecker');
-const SqlQuery = require('./Query').SqlQuery;
-const SqlFieldsQuery = require('./Query').SqlFieldsQuery;
-const ScanQuery = require('./Query').ScanQuery;
+import BinaryUtils from "./internal/BinaryUtils";
+import ArgumentChecker from "./internal/ArgumentChecker";
+import {ScanQuery, SqlFieldsQuery, SqlQuery} from "./Query";
+import BinaryCommunicator from "./internal/BinaryCommunicator";
+import {PRIMITIVE_TYPE} from "./internal/Constants";
+import { CompositeType } from "./ObjectType";
+import {CacheConfiguration} from "./CacheConfiguration";
 
 /**
  * Peek modes
@@ -55,7 +57,13 @@
  *
  * @hideconstructor
  */
-class CacheClient {
+export class CacheClient {
+    private _communicator: BinaryCommunicator;
+    private _cacheId: number;
+    private _keyType: PRIMITIVE_TYPE | CompositeType;
+    private _valueType: PRIMITIVE_TYPE | CompositeType;
+    private _name: string;
+    private _config: CacheConfiguration;
 
     static get PEEK_MODE() {
         return PEEK_MODE;
@@ -77,7 +85,7 @@
      * will do automatic mapping between some of the JavaScript types and object types -
      * according to the mapping table defined in the description of the {@link ObjectType} class.
      *
-     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} type - type of the keys in the cache:
+     * @param {PRIMITIVE_TYPE | CompositeType} type - type of the keys in the cache:
      *   - either a type code of primitive (simple) type
      *   - or an instance of class representing non-primitive (composite) type
      *   - or null (means the type is not specified).
@@ -86,7 +94,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    setKeyType(type) {
+    setKeyType(type: PRIMITIVE_TYPE | CompositeType) {
         BinaryUtils.checkObjectType(type, 'type');
         this._keyType = type;
         return this;
@@ -106,7 +114,7 @@
      * will do automatic mapping between some of the JavaScript types and object types -
      * according to the mapping table defined in the description of the {@link ObjectType} class.
      *
-     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} type - type of the values in the cache:
+     * @param {PRIMITIVE_TYPE | CompositeType} type - type of the values in the cache:
      *   - either a type code of primitive (simple) type
      *   - or an instance of class representing non-primitive (composite) type
      *   - or null (means the type is not specified).
@@ -115,7 +123,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    setValueType(type) {
+    setValueType(type: PRIMITIVE_TYPE | CompositeType) {
         BinaryUtils.checkObjectType(type, 'type');
         this._valueType = type;
         return this;
@@ -553,7 +561,7 @@
     /**
      * @ignore
      */
-    constructor(name, config, communicator) {
+    constructor(name: string, config: CacheConfiguration, communicator: BinaryCommunicator) {
         this._name = name;
         this._cacheId = CacheClient._calculateId(this._name);
         this._config = config;
@@ -745,19 +753,19 @@
     /**
      * @ignore
      */
-    _createAffinityHint(key) {
-        const affinityHint = {};
-        affinityHint.cacheId = this._cacheId;
-        affinityHint.key = key;
-        affinityHint.keyType = this._keyType;
-        return affinityHint;
+    _createAffinityHint(key: object): AffinityHint {
+        return new AffinityHint(this._cacheId, key, this._keyType);
     }
 }
 
 /**
  * A cache entry (key-value pair).
  */
-class CacheEntry {
+export class CacheEntry {
+
+    private _key: object;
+
+    private _value: object;
 
     /**
      * Public constructor.
@@ -767,7 +775,7 @@
      *
      * @return {CacheEntry} - new CacheEntry instance
      */
-    constructor(key, value) {
+    constructor(key: object, value: object) {
         this._key = key;
         this._value = value;
     }
@@ -791,5 +799,15 @@
     }
 }
 
-module.exports = CacheClient;
-module.exports.CacheEntry = CacheEntry;
+export class AffinityHint {
+
+    readonly cacheId: number;
+    readonly key: object;
+    readonly keyType: PRIMITIVE_TYPE | CompositeType;
+
+    constructor(cacheId: number, key: object, keyType: PRIMITIVE_TYPE | CompositeType) {
+        this.cacheId = cacheId;
+        this.key = key;
+        this.keyType = keyType;
+    }
+}
diff --git a/lib/CacheConfiguration.js b/src/CacheConfiguration.ts
similarity index 64%
rename from lib/CacheConfiguration.js
rename to src/CacheConfiguration.ts
index 75f0155..680dd54 100644
--- a/lib/CacheConfiguration.js
+++ b/src/CacheConfiguration.ts
@@ -17,12 +17,13 @@
 
 'use strict';
 
-const ComplexObjectType = require('./ObjectType').ComplexObjectType;
-const ObjectArrayType = require('./ObjectType').ObjectArrayType;
-const BinaryUtils = require('./internal/BinaryUtils');
-const BinaryCommunicator = require('./internal/BinaryCommunicator');
-const ArgumentChecker = require('./internal/ArgumentChecker');
-const Errors = require('./Errors');
+import {ComplexObjectType, CompositeType, ObjectArrayType} from "./ObjectType";
+import BinaryUtils from "./internal/BinaryUtils";
+import BinaryCommunicator from "./internal/BinaryCommunicator";
+import ArgumentChecker from "./internal/ArgumentChecker";
+import { IgniteClientError } from "./Errors";
+import MessageBuffer from "./internal/MessageBuffer";
+import {PRIMITIVE_TYPE} from "./internal/Constants";
 
 /**
  * Class representing Cache Key part of Ignite {@link CacheConfiguration}.
@@ -31,25 +32,29 @@
  *
  * See Apache Ignite documentation for details of every configuration setting.
  */
-class CacheKeyConfiguration {
+export class CacheKeyConfiguration {
+
+    private _typeName: string;
+
+    private _affinityKeyFieldName: string;
 
     /**
      * Public constructor.
      *
-     * @param {string} [typeName=null]
-     * @param {string} [affinityKeyFieldName=null]
+     * @param {string} [typeName=null] - Type name for which affinity field name is being defined.
+     * @param {string} [affinityKeyFieldName=null] - Affinity key field name.
      *
      * @return {CacheKeyConfiguration} - new CacheKeyConfiguration instance.
      */
-    constructor(typeName = null, affinityKeyFieldName = null) {
+    constructor(typeName: string = null, affinityKeyFieldName: string = null) {
         this._typeName = typeName;
         this._affinityKeyFieldName = affinityKeyFieldName;
     }
 
     /**
+     * Sets type name for which affinity field name is being defined.
      *
-     *
-     * @param {string} typeName
+     * @param {string} typeName - Type name for which affinity field name is being defined.
      *
      * @return {CacheKeyConfiguration} - the same instance of the CacheKeyConfiguration.
      */
@@ -59,18 +64,18 @@
     }
 
     /**
+     * Gets type name for which affinity field name is being defined.
      *
-     *
-     * @return {string}
+     * @return {string} - Type name for which affinity field name is being defined.
      */
     getTypeName() {
         return this._typeName;
     }
 
     /**
+     * Sets affinity key field name.
      *
-     *
-     * @param {string} affinityKeyFieldName
+     * @param {string} affinityKeyFieldName - Affinity key field name.
      *
      * @return {CacheKeyConfiguration} - the same instance of the CacheKeyConfiguration.
      */
@@ -80,9 +85,9 @@
     }
 
     /**
+     * Gets affinity key field name.
      *
-     *
-     * @return {string}
+     * @return {string} - Affinity key field name.
      */
     getAffinityKeyFieldName() {
         return this._affinityKeyFieldName;
@@ -114,7 +119,15 @@
  *
  * See Apache Ignite documentation for details of every configuration setting.
  */
-class QueryEntity {
+export class QueryEntity {
+    private _keyTypeName: string;
+    private _valueTypeName: string;
+    private _tableName: string;
+    private _keyFieldName: string;
+    private _valueFieldName: string;
+    private _fields: QueryField[];
+    private _aliases: Map<string, string>;
+    private _indexes: QueryIndex[];
 
     /**
      * Public constructor.
@@ -133,168 +146,171 @@
     }
 
     /**
+     * Sets key type name for this query entity.
      *
-     *
-     * @param {string} keyTypeName
+     * @param {string} keyTypeName - Key type name.
      *
      * @return {QueryEntity} - the same instance of the QueryEntity.
      */
-    setKeyTypeName(keyTypeName) {
+    setKeyTypeName(keyTypeName: string) {
         this._keyTypeName = keyTypeName;
         return this;
     }
 
     /**
+     * Gets key type name for this query entity.
      *
-     *
-     * @return {string}
+     * @return {string} - Key type name.
      */
     getKeyTypeName() {
         return this._keyTypeName;
     }
 
     /**
+     * Sets value type name for this query entity.
      *
-     *
-     * @param {string} valueTypeName
+     * @param {string} valueTypeName - Value type name.
      *
      * @return {QueryEntity} - the same instance of the QueryEntity.
      */
-    setValueTypeName(valueTypeName) {
+    setValueTypeName(valueTypeName: string) {
         this._valueTypeName = valueTypeName;
         return this;
     }
 
     /**
+     * Gets value type name for this query entity.
      *
-     *
-     * @return {string}
+     * @return {string} - Value type name.
      */
     getValueTypeName() {
         return this._valueTypeName;
     }
 
     /**
+     * Sets table name for this query entity.
      *
-     *
-     * @param {string} tableName
+     * @param {string} tableName - Table name.
      *
      * @return {QueryEntity} - the same instance of the QueryEntity.
      */
-    setTableName(tableName) {
+    setTableName(tableName: string) {
         this._tableName = tableName;
         return this;
     }
 
     /**
+     * Gets table name for this query entity.
      *
-     *
-     * @return {string}
+     * @return {string} - Table name.
      */
     getTableName() {
         return this._tableName;
     }
 
     /**
+     * Sets key field name.
      *
-     *
-     * @param {string} keyFieldName
+     * @param {string} keyFieldName - Key name.
      *
      * @return {QueryEntity} - the same instance of the QueryEntity.
      */
-    setKeyFieldName(keyFieldName) {
+    setKeyFieldName(keyFieldName: string) {
         this._keyFieldName = keyFieldName;
         return this;
     }
 
     /**
+     * Gets key field name.
      *
-     *
-     * @return {string}
+     * @return {string} - Key name.
      */
     getKeyFieldName() {
         return this._keyFieldName;
     }
 
     /**
+     * Sets value field name.
      *
-     *
-     * @param {string} valueFieldName
+     * @param {string} valueFieldName - Value name.
      *
      * @return {QueryEntity} - the same instance of the QueryEntity.
      */
-    setValueFieldName(valueFieldName) {
+    setValueFieldName(valueFieldName: string) {
         this._valueFieldName = valueFieldName;
         return this;
     }
 
     /**
+     * Gets value field name.
      *
-     *
-     * @return {string}
+     * @return {string} - Value name.
      */
     getValueFieldName() {
         return this._valueFieldName;
     }
 
     /**
+     * Sets query fields for this query pair. The order of the fields is important as it
+     * defines the order of columns returned by the 'select *' queries.
      *
-     *
-     * @param {Array<QueryField>} fields
+     * @param {Array<QueryField>} fields - Array of query fields.
      *
      * @return {QueryEntity} - the same instance of the QueryEntity.
      */
-    setFields(fields) {
+    setFields(fields: QueryField[]) {
         this._fields = fields;
         return this;
     }
 
     /**
+     * Gets query fields for this query pair. The order of the fields is
+     * defines the order of columns returned by the 'select *' queries.
      *
-     *
-     * @return {Array<QueryField>}
+     * @return {Array<QueryField>} - Array of query fields.
      */
     getFields() {
         return this._fields;
     }
 
     /**
+     * Sets mapping from a full property name in dot notation to an alias that will be
+     * used as SQL column name. Example: {"parent.name" -> "parentName"}.
      *
-     *
-     * @param {Map<string, string>} aliases
+     * @param {Map<string, string>} aliases - Aliases map.
      *
      * @return {QueryEntity} - the same instance of the QueryEntity.
      */
-    setAliases(aliases) {
+    setAliases(aliases: Map<string, string>) {
         this._aliases = aliases;
         return this;
     }
 
     /**
+     * Gets aliases map.
      *
-     *
-     * @return {Map<string, string>}
+     * @return {Map<string, string>} - Aliases map.
      */
     getAliases() {
         return this._aliases;
     }
 
     /**
+     * Sets a collection of index entities.
      *
-     *
-     * @param {Array<QueryIndex>} indexes
+     * @param {Array<QueryIndex>} indexes - Collection (array) of index entities.
      *
      * @return {QueryEntity} - the same instance of the QueryEntity.
      */
-    setIndexes(indexes) {
+    setIndexes(indexes: QueryIndex[]) {
         this._indexes = indexes;
         return this;
     }
 
     /**
+     * Gets a collection of index entities.
      *
-     *
-     * @return {Array<QueryIndex>}
+     * @return {Array<QueryIndex>} - Collection (array) of index entities.
      */
     getIndexes() {
         return this._indexes;
@@ -396,17 +412,28 @@
  *
  * See Apache Ignite documentation for details of every configuration setting.
  */
-class QueryField {
+export class QueryField {
+    private _name: string;
+    private _typeName: string;
+    private _isKeyField: boolean;
+    private _isNotNull: boolean;
+    private _precision: number;
+    private _scale: number;
+    private _communicator: BinaryCommunicator;
+    private _buffer: MessageBuffer;
+    private _defaultValue: object;
+    private _valueType: PRIMITIVE_TYPE | CompositeType;
+    private _index: number;
 
     /**
      * Public constructor.
      *
-     * @param {string} [name=null]
-     * @param {string} [typeName=null]
+     * @param {string} [name=null] - Query field name.
+     * @param {string} [typeName=null] - Query field type name.
      *
      * @return {QueryField} - new QueryField instance.
      */
-    constructor(name = null, typeName = null) {
+    constructor(name: string = null, typeName: string = null) {
         this._name = name;
         this._typeName = typeName;
         this._isKeyField = false;
@@ -421,9 +448,9 @@
     }
 
     /**
+     * Sets query field name.
      *
-     *
-     * @param {string} name
+     * @param {string} name - Query field name.
      *
      * @return {QueryField} - the same instance of the QueryField.
      */
@@ -433,18 +460,18 @@
     }
 
     /**
+     * Gets query field name.
      *
-     *
-     * @return {string}
+     * @return {string} - Query field name.
      */
     getName() {
         return this._name;
     }
 
     /**
+     * Sets query field type name.
      *
-     *
-     * @param {string} typeName
+     * @param {string} typeName - Query field type name.
      *
      * @return {QueryField} - the same instance of the QueryField.
      */
@@ -454,18 +481,18 @@
     }
 
     /**
+     * Gets query field type name.
      *
-     *
-     * @return {string}
+     * @return {string} - Query field type name.
      */
     getTypeName() {
         return this._typeName;
     }
 
     /**
+     * Sets if it is a key query field or not.
      *
-     *
-     * @param {boolean} isKeyField
+     * @param {boolean} isKeyField - True to make this query field a key field. False otherwise.
      *
      * @return {QueryField} - the same instance of the QueryField.
      */
@@ -475,18 +502,18 @@
     }
 
     /**
+     * Gets if it is a key query field or not.
      *
-     *
-     * @return {boolean}
+     * @return {boolean} - True if this query field is a key field. False otherwise.
      */
     getIsKeyField() {
         return this._isKeyField;
     }
 
     /**
+     * Sets if this query field must be checked for null.
      *
-     *
-     * @param {boolean} isNotNull
+     * @param {boolean} isNotNull - True if this query field must be checked for null. False otherwise.
      *
      * @return {QueryField} - the same instance of the QueryField.
      */
@@ -496,33 +523,33 @@
     }
 
     /**
+     * Gets if this query field must be checked for null.
      *
-     *
-     * @return {boolean}
+     * @return {boolean} - True if this query field must be checked for null. False otherwise.
      */
     getIsNotNull() {
         return this._isNotNull;
     }
 
     /**
+     * Sets query field default value.
      *
-     *
-     * @param {*} defaultValue
-     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [valueType=null] - type of the default value:
+     * @param {*} defaultValue - Query field default value.
+     * @param {PRIMITIVE_TYPE | CompositeType} [valueType=null] - type of the default value:
      *   - either a type code of primitive (simple) type
      *   - or an instance of class representing non-primitive (composite) type
      *   - or null (or not specified) that means the type is not specified
      *
      * @return {QueryField} - the same instance of the QueryField.
      */
-    setDefaultValue(defaultValue, valueType = null) {
+    setDefaultValue(defaultValue: object, valueType: PRIMITIVE_TYPE | CompositeType = null) {
         this._defaultValue = defaultValue;
         this._valueType = valueType;
         return this;
     }
 
     /**
-     *
+     * Gets query field default value.
      *
      * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [valueType=null] - type of the default value:
      *   - either a type code of primitive (simple) type
@@ -531,7 +558,7 @@
      *
      * @async
      *
-     * @return {*}
+     * @return {*} - Query field default value.
      */
     async getDefaultValue(valueType = null) {
         if (this._defaultValue === undefined) {
@@ -552,9 +579,9 @@
     }
 
     /**
+     * Sets query field precision.
      *
-     *
-     * @param {number} precision
+     * @param {number} precision - Query field precision.
      *
      * @return {QueryField} - the same instance of the QueryField.
      */
@@ -565,18 +592,18 @@
     }
 
     /**
+     * Gets query field precision.
      *
-     *
-     * @return {number}
+     * @return {number} - Query field precision.
      */
     getPrecision() {
         return this._precision;
     }
 
     /**
+     * Sets query field scale.
      *
-     *
-     * @param {number} scale
+     * @param {number} scale - Query field scale.
      *
      * @return {QueryField} - the same instance of the QueryField.
      */
@@ -587,9 +614,9 @@
     }
 
     /**
+     * Gets query field scale.
      *
-     *
-     * @return {number}
+     * @return {number} - Query field scale.
      */
     getScale() {
         return this._scale;
@@ -637,11 +664,11 @@
  * @property FULLTEXT 1
  * @property GEOSPATIAL 2
  */
- const INDEX_TYPE = Object.freeze({
-    SORTED : 0,
-    FULLTEXT : 1,
-    GEOSPATIAL : 2
-});
+ export enum INDEX_TYPE {
+    SORTED = 0,
+    FULLTEXT = 1,
+    GEOSPATIAL = 2
+}
 
 /**
  * Class representing one Query Index element of {@link QueryEntity} of Ignite {@link CacheConfiguration}.
@@ -650,17 +677,25 @@
  *
  * See Apache Ignite documentation for details of every configuration setting.
  */
-class QueryIndex {
+export class QueryIndex {
+
+    private _name: string;
+
+    private _inlineSize: number;
+
+    private _type: INDEX_TYPE;
+
+    private _fields: Map<string, boolean>;
 
     /**
      * Public constructor.
      *
-     * @param {string} [name=null]
-     * @param {string} [typeName=QueryIndex.INDEX_TYPE.SORTED]
+     * @param {string} [name=null] - Query index name.
+     * @param {string} type - Query index type name.
      *
      * @return {QueryIndex} - new QueryIndex instance.
      */
-    constructor(name = null, type = QueryIndex.INDEX_TYPE.SORTED) {
+    constructor(name: string = null, type: INDEX_TYPE = INDEX_TYPE.SORTED) {
         this._name = name;
         this.setType(type);
         this._inlineSize = -1;
@@ -672,9 +707,9 @@
     }
 
     /**
+     * Sets query index name. Will be automatically set if not provided by a user.
      *
-     *
-     * @param {string} name
+     * @param {string} name - Query index name.
      *
      * @return {QueryIndex} - the same instance of the QueryIndex.
      */
@@ -684,42 +719,50 @@
     }
 
     /**
+     * Gets query index name.
      *
-     *
-     * @return {string}
+     * @return {string} - Query index name.
      */
     getName() {
         return this._name;
     }
 
     /**
+     * Sets query index type.
      *
-     *
-     * @param {QueryIndex.INDEX_TYPE} type
+     * @param {INDEX_TYPE} type - Query index type.
      *
      * @return {QueryIndex} - the same instance of the QueryIndex.
      *
      * @throws {IgniteClientError} if error.
      */
-    setType(type) {
+    setType(type: INDEX_TYPE): QueryIndex {
         ArgumentChecker.hasValueFrom(type, 'type', false, QueryIndex.INDEX_TYPE);
         this._type = type;
         return this;
     }
 
     /**
+     * Gets query index type.
      *
-     *
-     * @return {QueryIndex.INDEX_TYPE}
+     * @return {QueryIndex.INDEX_TYPE} - Query index type.
      */
     getType() {
         return this._type;
     }
 
     /**
+     * Sets index inline size in bytes. When enabled, a part of the indexed value is placed directly
+     * to the index pages, thus minimizing data page accesses and increasing query performance. Allowed values:
+     *   - -1 (default) - determine inline size automatically (see below)
+     *   - 0 - index inline is disabled (not recommended)
+     *   - positive value - fixed index inline
      *
+     * When set to -1, Ignite will try to detect inline size automatically. It will be no more than
+     * CacheConfiguration.getSqlIndexInlineMaxSize(). Index inline will be enabled for all fixed-length types,
+     * but will not be enabled for String.
      *
-     * @param {number} inlineSize
+     * @param {number} inlineSize - Index inline size in bytes.
      *
      * @return {QueryIndex} - the same instance of the QueryIndex.
      */
@@ -729,30 +772,30 @@
     }
 
     /**
+     * Gets index inline size in bytes.
      *
-     *
-     * @return {number}
+     * @return {number} - Index inline size in bytes.
      */
     getInlineSize() {
         return this._inlineSize;
     }
 
     /**
+     * Sets fields included in the index.
      *
-     *
-     * @param {Map<string, boolean>} fields
+     * @param {Map<string, boolean>} fields - Map of the index fields.
      *
      * @return {QueryIndex} - the same instance of the QueryIndex.
      */
-    setFields(fields) {
+    setFields(fields: Map<string, boolean>): QueryIndex {
         this._fields = fields;
         return this;
     }
 
     /**
+     * Gets fields included in the index.
      *
-     *
-     * @return {Map<string, boolean>}
+     * @return {Map<string, boolean>} - Map of the index fields.
      */
     getFields() {
         return this._fields;
@@ -945,7 +988,8 @@
  *
  * See Apache Ignite documentation for details of every configuration setting.
  */
-class CacheConfiguration {
+export class CacheConfiguration {
+    private _properties: Map<number, object>;
 
     /**
      * Public constructor.
@@ -953,7 +997,7 @@
      * @return {CacheConfiguration} - new CacheConfiguration instance.
      */
     constructor() {
-        this._properties = new Map();
+        this._properties = new Map<number, object>();
     }
 
     static get CACHE_ATOMICITY_MODE() {
@@ -977,9 +1021,9 @@
     }
 
     /**
+     * Sets cache atomicity mode.
      *
-     *
-     * @param {CacheConfiguration.CACHE_ATOMICITY_MODE} atomicityMode
+     * @param {CacheConfiguration.CACHE_ATOMICITY_MODE} atomicityMode - Cache atomicity mode.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      *
@@ -992,18 +1036,18 @@
     }
 
     /**
+     * Gets cache atomicity mode.
      *
-     *
-     * @return {CacheConfiguration.CACHE_ATOMICITY_MODE}
+     * @return {CacheConfiguration.CACHE_ATOMICITY_MODE} - Cache atomicity mode.
      */
     getAtomicityMode() {
         return this._properties.get(PROP_ATOMICITY_MODE);
     }
 
     /**
+     * Sets number of nodes used to back up single partition for {@link CacheConfiguration.CACHE_MODE}.PARTITIONED cache.
      *
-     *
-     * @param {number} backups
+     * @param {number} backups - Number of backup nodes for one partition.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1013,18 +1057,18 @@
     }
 
     /**
+     * Gets number of nodes used to back up single partition for {@link CacheConfiguration.CACHE_MODE}.PARTITIONED cache.
      *
-     *
-     * @return {number}
+     * @return {number} - Number of backup nodes for one partition.
      */
     getBackups() {
         return this._properties.get(PROP_BACKUPS);
     }
 
     /**
+     * Sets caching mode.
      *
-     *
-     * @param {CacheConfiguration.CACHE_MODE} cacheMode
+     * @param {CacheConfiguration.CACHE_MODE} cacheMode - Caching mode.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      *
@@ -1037,18 +1081,21 @@
     }
 
     /**
+     * Gets caching mode.
      *
-     *
-     * @return {CacheConfiguration.CACHE_MODE}
+     * @return {CacheConfiguration.CACHE_MODE} - Caching mode.
      */
     getCacheMode() {
         return this._properties.get(PROP_CACHE_MODE);
     }
 
     /**
+     * Sets the flag indicating whether a copy of the value stored in the on-heap cache
+     * should be created for a cache operation return the value. Also, if this flag
+     * is set, copies are created for values passed to CacheInterceptor and to CacheEntryProcessor.
+     * If the on-heap cache is disabled then this flag is of no use.
      *
-     *
-     * @param {boolean} copyOnRead
+     * @param {boolean} copyOnRead - Copy on read flag.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1058,18 +1105,19 @@
     }
 
     /**
+     * Gets copy on read flag.
      *
-     *
-     * @return {boolean}
+     * @return {boolean} - Copy on read flag.
      */
     getCopyOnRead() {
         return this._properties.get(PROP_COPY_ON_READ);
     }
 
     /**
+     * Sets a name of DataRegionConfiguration for this cache.
      *
-     *
-     * @param {string} dataRegionName
+     * @param {string} dataRegionName - DataRegionConfiguration name. Can be null
+     *  (default DataRegionConfiguration will be used) but should not be empty.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1079,18 +1127,20 @@
     }
 
     /**
+     * Gets the name of DataRegionConfiguration for this cache.
      *
-     *
-     * @return {string}
+     * @return {string} - DataRegionConfiguration name.
      */
     getDataRegionName() {
         return this._properties.get(PROP_DATA_REGION_NAME);
     }
 
     /**
+     * Sets eager ttl flag. If there is at least one cache configured with this flag set to true,
+     * Ignite will create a single thread to clean up expired entries in background.
+     * When flag is set to false, expired entries will be removed on next entry access.
      *
-     *
-     * @param {boolean} eagerTtl
+     * @param {boolean} eagerTtl - True if Ignite should eagerly remove expired cache entries.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1100,18 +1150,20 @@
     }
 
     /**
+     * Gets eager ttl flag. If there is at least one cache configured with this flag set to true,
+     * Ignite will create a single thread to clean up expired entries in background.
+     * When flag is set to false, expired entries will be removed on next entry access.
      *
-     *
-     * @return {boolean}
+     * @return {boolean} - Flag indicating whether Ignite will eagerly remove expired entries.
      */
     getEagerTtl() {
         return this._properties.get(PROP_EAGER_TTL);
     }
 
     /**
+     * Enables or disables statistics for this cache.
      *
-     *
-     * @param {boolean} statisticsEnabled
+     * @param {boolean} statisticsEnabled - True to enable, false to disable.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1121,18 +1173,20 @@
     }
 
     /**
+     * Gets if statistics are enabled for this cache.
      *
-     *
-     * @return {boolean}
+     * @return {boolean} - True if enabled, false if disabled.
      */
     getStatisticsEnabled() {
         return this._properties.get(PROP_STATISTICS_ENABLED);
     }
 
     /**
+     * Sets the cache group name. Caches with the same group name share single underlying 'physical' cache
+     * (partition set), but are logically isolated. Grouping caches reduces overall overhead, since
+     * internal data structures are shared.
      *
-     *
-     * @param {string} groupName
+     * @param {string} groupName - Cache group name.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1142,18 +1196,18 @@
     }
 
     /**
+     * Gets the cache group name.
      *
-     *
-     * @return {string}
+     * @return {string} - Cache group name.
      */
     getGroupName() {
         return this._properties.get(PROP_GROUP_NAME);
     }
 
     /**
+     * Sets default lock timeout in milliseconds.
      *
-     *
-     * @param {number} lockTimeout
+     * @param {number} lockTimeout - Default lock timeout.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1163,18 +1217,19 @@
     }
 
     /**
+     * Gets default lock acquisition timeout.
      *
-     *
-     * @return {number}
+     * @return {number} - Default lock timeout.
      */
     getDefaultLockTimeout() {
         return this._properties.get(PROP_DEFAULT_LOCK_TIMEOUT);
     }
 
     /**
+     * Sets maximum number of allowed concurrent asynchronous operations. 0 - the number of concurrent asynchronous
+     * operations is unlimited.
      *
-     *
-     * @param {number} maxConcurrentAsyncOperations
+     * @param {number} maxConcurrentAsyncOperations - Maximum number of concurrent asynchronous operations.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1184,18 +1239,21 @@
     }
 
     /**
+     * Gets maximum number of allowed concurrent asynchronous operations.
+     * If 0 returned then number of concurrent asynchronous operations is unlimited.
      *
-     *
-     * @return {number}
+     * @return {number} - Maximum number of concurrent asynchronous operations or 0 if unlimited.
      */
     getMaxConcurrentAsyncOperations() {
         return this._properties.get(PROP_MAX_CONCURRENT_ASYNC_OPS);
     }
 
     /**
+     * Sets maximum number of query iterators that can be stored. Iterators are stored to support query
+     * pagination when each page of data is sent to user's node only on demand. Increase this property
+     * if you are running and processing lots of queries in parallel.
      *
-     *
-     * @param {number} maxQueryIterators
+     * @param {number} maxQueryIterators - Maximum number of query iterators that can be stored.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1205,18 +1263,18 @@
     }
 
     /**
+     * Gets maximum number of query iterators that can be stored.
      *
-     *
-     * @return {number}
+     * @return {number} - Maximum number of query iterators that can be stored.
      */
     getMaxQueryIterators() {
         return this._properties.get(PROP_MAX_QUERY_ITERATORS);
     }
 
     /**
+     * Enables/disables on-heap cache for the off-heap based page memory.
      *
-     *
-     * @param {boolean} isOnheapCacheEnabled
+     * @param {boolean} isOnheapCacheEnabled - On-heap cache enabled flag.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1226,18 +1284,19 @@
     }
 
     /**
+     * Checks if the on-heap cache is enabled for the off-heap based page memory.
      *
-     *
-     * @return {boolean}
+     * @return {boolean} - On-heap cache enabled flag.
      */
     getIsOnheapCacheEnabled() {
         return this._properties.get(PROP_IS_ONHEAP_CACHE_ENABLED);
     }
 
     /**
+     * Sets partition loss policy. This policy defines how Ignite will react to a situation when
+     * all nodes for some partition leave the cluster.
      *
-     *
-     * @param {CacheConfiguration.PARTITION_LOSS_POLICY} partitionLossPolicy
+     * @param {CacheConfiguration.PARTITION_LOSS_POLICY} partitionLossPolicy - Partition loss policy.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      *
@@ -1250,18 +1309,20 @@
     }
 
     /**
+     * Gets partition loss policy. This policy defines how Ignite will react to a situation when
+     * all nodes for some partition leave the cluster.
      *
-     *
-     * @return {CacheConfiguration.PARTITION_LOSS_POLICY}
+     * @return {CacheConfiguration.PARTITION_LOSS_POLICY} - Partition loss policy.
      */
     getPartitionLossPolicy() {
         return this._properties.get(PROP_PARTITION_LOSS_POLICY);
     }
 
     /**
+     * Sets size of queries detail metrics that will be stored in memory for monitoring purposes.
+     * If 0, then history will not be collected. Note, larger number may lead to higher memory consumption.
      *
-     *
-     * @param {number} queryDetailMetricsSize
+     * @param {number} queryDetailMetricsSize - Maximum number of latest queries metrics that will be stored in memory.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1271,18 +1332,21 @@
     }
 
     /**
+     * Gets size of queries detail metrics that will be stored in memory for monitoring purposes.
+     * If 0, then history will not be collected. Note, larger number may lead to higher memory consumption.
      *
-     *
-     * @return {number}
+     * @return {number} - Maximum number of query metrics that will be stored in memory.
      */
     getQueryDetailMetricsSize() {
         return this._properties.get(PROP_QUERY_DETAIL_METRICS_SIZE);
     }
 
     /**
+     * Defines a hint to query execution engine on desired degree of parallelism within a single node.
+     * Query executor may or may not use this hint depending on estimated query costs.
+     * Query executor may define certain restrictions on parallelism depending on query type and/or cache type.
      *
-     *
-     * @param {number} queryParallelism
+     * @param {number} queryParallelism - Query parallelism.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1292,18 +1356,20 @@
     }
 
     /**
+     * Gets query parallelism parameter which is a hint to query execution engine on desired degree of
+     * parallelism within a single node.
      *
-     *
-     * @return {number}
+     * @return {number} - Query parallelism.
      */
     getQueryParallelism() {
         return this._properties.get(PROP_QUERY_PARALLELISM);
     }
 
     /**
+     * Sets read from backup flag.
      *
-     *
-     * @param {boolean} readFromBackup
+     * @param {boolean} readFromBackup - True to allow reads from backups. False - data always
+     * should be read from primary node and never from backup.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1313,18 +1379,20 @@
     }
 
     /**
+     * Gets flag indicating whether data can be read from backup.
      *
-     *
-     * @return {boolean}
+     * @return {boolean} - true if data can be read from backup node or false if data always
+     *  should be read from primary node and never from backup.
      */
     getReadFromBackup() {
         return this._properties.get(PROP_READ_FROM_BACKUP);
     }
 
     /**
+     * Sets rebalance batch size (to be loaded within a single rebalance message). Rebalancing algorithm will split
+     * total data set on every node into multiple batches prior to sending data.
      *
-     *
-     * @param {number} rebalanceBatchSize
+     * @param {number} rebalanceBatchSize - Rebalance batch size (size in bytes of a single rebalance message).
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1334,18 +1402,20 @@
     }
 
     /**
+     * Gets size (in number bytes) to be loaded within a single rebalance message.
      *
-     *
-     * @return {number}
+     * @return {number} - Size in bytes of a single rebalance message.
      */
     getRebalanceBatchSize() {
         return this._properties.get(PROP_REBALANCE_BATCH_SIZE);
     }
 
     /**
+     * To gain better rebalancing performance supplier node can provide more than one batch at rebalancing start
+     * and provide one new to each next demand request. Sets number of batches generated by supply node at
+     * rebalancing start. Minimum is 1.
      *
-     *
-     * @param {number} rebalanceBatchesPrefetchCount
+     * @param {number} rebalanceBatchesPrefetchCount - Batches count.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1355,18 +1425,25 @@
     }
 
     /**
+     * To gain better rebalancing performance supplier node can provide more than one batch at rebalancing start
+     * and provide one new to each next demand request. Gets number of batches generated by supply node at
+     * rebalancing start. Minimum is 1.
      *
-     *
-     * @return {number}
+     * @return {number} - Batches count.
      */
     getRebalanceBatchesPrefetchCount() {
         return this._properties.get(PROP_REBALANCE_BATCHES_PREFETCH_COUNT);
     }
 
     /**
+     * Sets delay in milliseconds upon a node joining or leaving topology (or crash) after which rebalancing should be
+     * started automatically. Rebalancing should be delayed if you plan to restart nodes after they leave topology,
+     * or if you plan to start multiple nodes at once or one after another and don't want to repartition and rebalance
+     * until all nodes are started.
      *
-     *
-     * @param {number} rebalanceDelay
+     * @param {number} rebalanceDelay - Rebalance delay to set. 0 to start rebalancing immediately,
+     *  -1 to start rebalancing manually, or positive value to specify delay in milliseconds after which rebalancing
+     *  should start automatically.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1376,18 +1453,18 @@
     }
 
     /**
+     * Gets rebalance delay.
      *
-     *
-     * @return {number}
+     * @return {number} - Rebalance delay.
      */
     getRebalanceDelay() {
         return this._properties.get(PROP_REBALANCE_DELAY);
     }
 
     /**
+     * Sets rebalance mode for distributed cache.
      *
-     *
-     * @param {CacheConfiguration.REABALANCE_MODE} rebalanceMode
+     * @param {CacheConfiguration.REABALANCE_MODE} rebalanceMode - Rebalance mode.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      *
@@ -1400,18 +1477,20 @@
     }
 
     /**
+     * Gets rebalance mode for distributed cache.
      *
-     *
-     * @return {CacheConfiguration.REABALANCE_MODE}
+     * @return {CacheConfiguration.REABALANCE_MODE} - Rebalance mode.
      */
     getRebalanceMode() {
         return this._properties.get(PROP_REBALANCE_MODE);
     }
 
     /**
+     * Sets cache rebalance order. Rebalance order can be set to non-zero value for caches with SYNC or
+     * ASYNC rebalance modes only. If cache rebalance order is positive, rebalancing for this cache will be started
+     * only when rebalancing for all caches with smaller rebalance order will be completed.
      *
-     *
-     * @param {number} rebalanceOrder
+     * @param {number} rebalanceOrder - Cache rebalance order.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1421,18 +1500,20 @@
     }
 
     /**
+     * Gets cache rebalance order.
      *
-     *
-     * @return {number}
+     * @return {number} - Cache rebalance order.
      */
     getRebalanceOrder() {
         return this._properties.get(PROP_REBALANCE_ORDER);
     }
 
     /**
+     * Sets time in milliseconds to wait between rebalance messages to avoid overloading of CPU or network. This parameter
+     * helps tune the amount of time to wait between rebalance messages to make sure that rebalancing process does not
+     * have any negative performance impact.
      *
-     *
-     * @param {number} rebalanceThrottle
+     * @param {number} rebalanceThrottle - Time in millis to wait between rebalance messages, 0 to disable throttling.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1442,18 +1523,18 @@
     }
 
     /**
+     * Gets time in milliseconds to wait between rebalance messages to avoid overloading of CPU or network.
      *
-     *
-     * @return {number}
+     * @return {number} - Time in millis to wait between rebalance messages, 0 - throttling disabled.
      */
     getRebalanceThrottle() {
         return this._properties.get(PROP_REBALANCE_THROTTLE);
     }
 
     /**
+     * Sets rebalance timeout (ms).
      *
-     *
-     * @param {number} rebalanceTimeout
+     * @param {number} rebalanceTimeout - Rebalance timeout (ms).
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1463,18 +1544,20 @@
     }
 
     /**
+     * Gets rebalance timeout (ms).
      *
-     *
-     * @return {number}
+     * @return {number} - Rebalance timeout (ms).
      */
     getRebalanceTimeout() {
         return this._properties.get(PROP_REBALANCE_TIMEOUT);
     }
 
     /**
+     * Sets sqlEscapeAll flag. If true all the SQL table and field names will be escaped with double quotes like
+     * ("tableName"."fieldsName"). This enforces case sensitivity for field names and also allows having special
+     * characters in table and field names.
      *
-     *
-     * @param {boolean} sqlEscapeAll
+     * @param {boolean} sqlEscapeAll - Flag value.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1484,18 +1567,18 @@
     }
 
     /**
+     * Gets sqlEscapeAll flag.
      *
-     *
-     * @return {boolean}
+     * @return {boolean} - Flag value.
      */
     getSqlEscapeAll() {
         return this._properties.get(PROP_SQL_ESCAPE_ALL);
     }
 
     /**
+     * Sets maximum inline size for sql indexes.
      *
-     *
-     * @param {number} sqlIndexInlineMaxSize
+     * @param {number} sqlIndexInlineMaxSize - Maximum payload size for offheap indexes.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1505,18 +1588,22 @@
     }
 
     /**
+     * Gets maximum inline size for sql indexes.
      *
-     *
-     * @return {number}
+     * @return {number} - Maximum payload size for offheap indexes.
      */
     getSqlIndexInlineMaxSize() {
         return this._properties.get(PROP_SQL_INDEX_INLINE_MAX_SIZE);
     }
 
     /**
+     * Sets sql schema to be used for current cache. This name will correspond to SQL ANSI-99 standard. Nonquoted
+     * identifiers are not case sensitive. Quoted identifiers are case sensitive. Be aware of using the same string
+     * in case sensitive and case insensitive manner simultaneously, since behaviour for such case is not specified.
+     * When sqlSchema is not specified, quoted cacheName is used instead. sqlSchema could not be an empty string.
+     * Has to be "\"\"" (quoted empty string) instead.
      *
-     *
-     * @param {string} sqlSchema
+     * @param {string} sqlSchema - Schema name for current cache according to SQL ANSI-99. Should not be null.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      */
@@ -1526,18 +1613,20 @@
     }
 
     /**
+     * Gets custom name of the sql schema. If custom sql schema is not set then undefined will be returned and quoted
+     * case sensitive name will be used as sql schema.
      *
-     *
-     * @return {string}
+     * @return {string} - Schema name for current cache according to SQL ANSI-99. Could be undefined.
      */
     getSqlSchema() {
         return this._properties.get(PROP_SQL_SCHEMA);
     }
 
     /**
+     * Sets write synchronization mode. Default synchronization mode is
+     * {@link CacheConfiguration.WRITE_SYNCHRONIZATION_MODE}.PRIMARY_SYNC.
      *
-     *
-     * @param {CacheConfiguration.WRITE_SYNCHRONIZATION_MODE} writeSynchronizationMode
+     * @param {CacheConfiguration.WRITE_SYNCHRONIZATION_MODE} writeSynchronizationMode - Write synchronization mode
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      *
@@ -1550,18 +1639,19 @@
     }
 
     /**
+     * Gets write synchronization mode. This mode controls whether the main caller should wait for update on
+     * other nodes to complete or not.
      *
-     *
-     * @return {CacheConfiguration.WRITE_SYNCHRONIZATION_MODE}
+     * @return {CacheConfiguration.WRITE_SYNCHRONIZATION_MODE} - Write synchronization mode.
      */
     getWriteSynchronizationMode() {
         return this._properties.get(PROP_WRITE_SYNCHRONIZATION_MODE);
     }
 
     /**
+     * Sets cache key configurations.
      *
-     *
-     * @param {...CacheKeyConfiguration} keyConfigurations
+     * @param {...CacheKeyConfiguration} keyConfigurations - Cache key configurations.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      *
@@ -1574,33 +1664,33 @@
     }
 
     /**
+     * Gets cache key configurations.
      *
-     *
-     * @return {Array<CacheKeyConfiguration>}
+     * @return {Array<CacheKeyConfiguration>} - Array of cache key configurations.
      */
     getKeyConfigurations() {
         return this._properties.get(PROP_CACHE_KEY_CONFIGURATION);
     }
 
     /**
+     * Sets query entities configuration.
      *
-     *
-     * @param {...QueryEntity} queryEntities
+     * @param {...QueryEntity} queryEntities - Query entities configuration.
      *
      * @return {CacheConfiguration} - the same instance of the CacheConfiguration.
      *
      * @throws {IgniteClientError} if error.
      */
-    setQueryEntities(...queryEntities) {
+    setQueryEntities(...queryEntities: QueryEntity[]) {
         ArgumentChecker.hasType(queryEntities, 'queryEntities', true, QueryEntity);
         this._properties.set(PROP_QUERY_ENTITY, queryEntities);
         return this;
     }
 
     /**
+     * Gets a collection (array) of configured query entities.
      *
-     *
-     * @return {Array<QueryEntity>}
+     * @return {Array<QueryEntity>} - Array of query entities configurations.
      */
     getQueryEntities() {
         return this._properties.get(PROP_QUERY_ENTITY);
@@ -1653,7 +1743,7 @@
                 }
                 return;
             default:
-                throw Errors.IgniteClientError.internalError();
+                throw IgniteClientError.internalError();
         }
     }
 
@@ -1722,13 +1812,7 @@
                 }
                 return;
             default:
-                throw Errors.IgniteClientError.internalError();
+                throw IgniteClientError.internalError();
         }
     }
 }
-
-module.exports = CacheConfiguration;
-module.exports.QueryEntity = QueryEntity;
-module.exports.QueryField = QueryField;
-module.exports.QueryIndex = QueryIndex;
-module.exports.CacheKeyConfiguration = CacheKeyConfiguration;
diff --git a/lib/Cursor.js b/src/Cursor.ts
similarity index 74%
rename from lib/Cursor.js
rename to src/Cursor.ts
index 39eea21..30bdc0a 100644
--- a/lib/Cursor.js
+++ b/src/Cursor.ts
@@ -17,32 +17,45 @@
 
 'use strict';
 
-const Errors = require('./Errors');
-const BinaryUtils = require('./internal/BinaryUtils');
-const BinaryObject = require('./BinaryObject');
+const Long = require('long');
+import BinaryUtils, { OPERATION } from './internal/BinaryUtils';
+import BinaryCommunicator from "./internal/BinaryCommunicator";
+import {PRIMITIVE_TYPE} from "./internal/Constants";
+import {CompositeType} from "./ObjectType";
+import MessageBuffer from "./internal/MessageBuffer";
+import {CacheEntry} from "./CacheClient";
 
-/**
- * Class representing a cursor to obtain results of SQL and Scan query operations.
- *
- * The class has no public constructor. An instance of this class is obtained
- * via query() method of {@link CacheClient} objects.
- * One instance of this class returns results of one SQL or Scan query operation.
- *
- * @hideconstructor
- */
-class Cursor {
+export abstract class BaseCursor<T> {
+
+    protected _id: Long;
+
+    protected _hasNext: boolean;
+
+    protected _communicator: BinaryCommunicator;
+
+    protected _operation: OPERATION;
+
+    protected _buffer: MessageBuffer;
+
+    protected _keyType: object;
+
+    protected _valueType: object;
+
+    protected _values: T[];
+
+    protected _valueIndex: number;
 
     /**
-     * Returns one element (cache entry - key-value pair) from the query results.
+     * Returns one element (cache entry) from the query results.
      *
      * Every new call returns the next cache entry from the query results.
      * If the method returns null, no more entries are available.
      *
      * @async
      *
-     * @return {Promise<CacheEntry>} - a cache entry (key-value pair).
+     * @return {Promise<T>} - a cache entry.
      */
-    async getValue() {
+    async getValue(): Promise<T> {
         if (!this._values || this._valueIndex >= this._values.length) {
             await this._getValues();
             this._valueIndex = 0;
@@ -60,25 +73,24 @@
      *
      * @return {boolean} - true if more cache entries are available, false otherwise.
      */
-    hasMore() {
+    hasMore(): boolean {
         return this._hasNext ||
             this._values && this._valueIndex < this._values.length;
     }
 
     /**
-     * Returns all elements (cache entries - key-value pairs) from the query results.
+     * Returns all elements (cache entries) from the query results.
      *
      * May be used instead of getValue() method if the number of returned entries
      * is relatively small and will not cause memory utilization issues.
      *
      * @async
      *
-     * @return {Promise<Array<CacheEntry>>} - all cache entries (key-value pairs)
-     *   returned by SQL or Scan query.
+     * @return {Promise<Array<T>>} - all cache entries returned by SQL or Scan query.
      */
-    async getAll() {
-        let result = new Array();
-        let values;
+    async getAll(): Promise<T[]> {
+        let result: T[] = [];
+        let values: T[];
         do {
             values = await this._getValues();
             if (values) {
@@ -112,7 +124,7 @@
     /**
      * @ignore
      */
-    constructor(communicator, operation, buffer, keyType = null, valueType = null) {
+    constructor(communicator: BinaryCommunicator, operation: OPERATION, buffer: MessageBuffer, keyType = null, valueType = null) {
         this._communicator = communicator;
         this._operation = operation;
         this._buffer = buffer;
@@ -144,7 +156,7 @@
     /**
      * @ignore
      */
-    async _getValues() {
+    async _getValues(): Promise<T[]> {
         if (!this._buffer && this._hasNext) {
             await this._getNext();
         }
@@ -170,12 +182,7 @@
     /**
      * @ignore
      */
-    async _readRow(buffer) {
-        const CacheEntry = require('./CacheClient').CacheEntry;
-        return new CacheEntry(
-            await this._communicator.readObject(buffer, this._keyType),
-            await this._communicator.readObject(buffer, this._valueType));
-    }
+    abstract _readRow(buffer: MessageBuffer): Promise<T>;
 
     /**
      * @ignore
@@ -191,6 +198,38 @@
 }
 
 /**
+ * Class representing a cursor to obtain results of SQL and Scan query operations.
+ *
+ * The class has no public constructor. An instance of this class is obtained
+ * via query() method of {@link CacheClient} objects.
+ * One instance of this class returns results of one SQL or Scan query operation.
+ *
+ * @hideconstructor
+ */
+export class Cursor extends BaseCursor<CacheEntry> {
+
+    /** Private methods */
+
+    /**
+     * @ignore
+     */
+    constructor(communicator: BinaryCommunicator, operation: OPERATION, buffer: MessageBuffer, keyType = null, valueType = null) {
+        super(communicator, operation, buffer, keyType, valueType);
+    }
+
+
+    /**
+     * @ignore
+     */
+    async _readRow(buffer: MessageBuffer): Promise<CacheEntry> {
+        return new CacheEntry(
+            await this._communicator.readObject(buffer, this._keyType),
+            await this._communicator.readObject(buffer, this._valueType));
+    }
+
+}
+
+/**
  * Class representing a cursor to obtain results of SQL Fields query operation.
  *
  * The class has no public constructor. An instance of this class is obtained
@@ -200,7 +239,13 @@
  * @hideconstructor
  * @extends Cursor
  */
-class SqlFieldsCursor extends Cursor {
+export class SqlFieldsCursor extends BaseCursor<Array<object>> {
+
+    private _fieldCount: number;
+
+    private _fieldTypes: (PRIMITIVE_TYPE | CompositeType)[];
+
+    private _fieldNames: string[];
 
     /**
      * Returns one element (array with values of the fields) from the query results.
@@ -213,7 +258,7 @@
      * @return {Promise<Array<*>>} - array with values of the fields requested by the query.
      *
      */
-    async getValue() {
+    async getValue(): Promise<Array<object>> {
         return await super.getValue();
     }
 
@@ -229,7 +274,7 @@
      *   Every element of the array is an array with values of the fields requested by the query.
      *
      */
-    async getAll() {
+    async getAll(): Promise<Array<object>[]> {
         return await super.getAll();
     }
 
@@ -241,7 +286,7 @@
      * @return {Array<string>} - field names.
      *   The order of names corresponds to the order of field values returned in the results of the query.
      */
-    getFieldNames() {
+    getFieldNames(): string[] {
         return this._fieldNames;
     }
 
@@ -252,7 +297,7 @@
      * will try to make automatic mapping between JavaScript types and Ignite object types -
      * according to the mapping table defined in the description of the {@link ObjectType} class.
      *
-     * @param {...ObjectType.PRIMITIVE_TYPE | CompositeType} fieldTypes - types of the returned fields.
+     * @param {...PRIMITIVE_TYPE | CompositeType} fieldTypes - types of the returned fields.
      *   The order of types must correspond the order of field values returned in the results of the query.
      *   A type of every field can be:
      *   - either a type code of primitive (simple) type
@@ -261,7 +306,7 @@
      *
      * @return {SqlFieldsCursor} - the same instance of the SqlFieldsCursor.
      */
-    setFieldTypes(...fieldTypes) {
+    setFieldTypes(...fieldTypes: Array<PRIMITIVE_TYPE | CompositeType>) {
         this._fieldTypes = fieldTypes;
         return this;
     }
@@ -271,15 +316,15 @@
     /**
      * @ignore
      */
-    constructor(communicator, buffer) {
-        super(communicator, BinaryUtils.OPERATION.QUERY_SQL_FIELDS_CURSOR_GET_PAGE, buffer);
+    constructor(communicator: BinaryCommunicator, buffer: MessageBuffer) {
+        super(communicator, OPERATION.QUERY_SQL_FIELDS_CURSOR_GET_PAGE, buffer);
         this._fieldNames = [];
     }
 
     /**
      * @ignore
      */
-    async _readFieldNames(buffer, includeFieldNames) {
+    async _readFieldNames(buffer: MessageBuffer, includeFieldNames: boolean) {
         this._id = buffer.readLong();
         this._fieldCount = buffer.readInteger();
         if (includeFieldNames) {
@@ -292,8 +337,8 @@
     /**
      * @ignore
      */
-    async _readRow(buffer) {
-        let values = new Array(this._fieldCount);
+    async _readRow(buffer: MessageBuffer): Promise<Array<object>> {
+        let values: object[] = new Array(this._fieldCount);
         let fieldType;
         for (let i = 0; i < this._fieldCount; i++) {
             fieldType = this._fieldTypes && i < this._fieldTypes.length ? this._fieldTypes[i] : null;
@@ -302,6 +347,3 @@
         return values;
     }
 }
-
-module.exports.Cursor = Cursor;
-module.exports.SqlFieldsCursor = SqlFieldsCursor;
diff --git a/lib/EnumItem.js b/src/EnumItem.ts
similarity index 74%
rename from lib/EnumItem.js
rename to src/EnumItem.ts
index 5e80da9..5c236a3 100644
--- a/lib/EnumItem.js
+++ b/src/EnumItem.ts
@@ -17,9 +17,11 @@
 
 'use strict';
 
-const Util = require('util');
-const ArgumentChecker = require('./internal/ArgumentChecker');
-const Errors = require('./Errors');
+import * as Util from "util";
+import ArgumentChecker from "./internal/ArgumentChecker";
+import { IgniteClientError } from "./Errors";
+import BinaryCommunicator from "./internal/BinaryCommunicator";
+import MessageBuffer from "./internal/MessageBuffer";
 
 /**
  * Class representing an item of Ignite enum type.
@@ -35,7 +37,15 @@
  * To distinguish one item from another, the Ignite client analyzes the optional fields in the following order:
  * ordinal, name, value.
  */
-class EnumItem {
+export class EnumItem {
+
+    private _typeId: number;
+
+    private _ordinal: number;
+
+    private _name: string;
+
+    private _value: number;
 
     /**
      * Public constructor.
@@ -46,7 +56,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    constructor(typeId) {
+    constructor(typeId: number) {
         this.setTypeId(typeId);
         this._ordinal = null;
         this._name = null;
@@ -58,7 +68,7 @@
      *
      * @return {number} - Id of the enum type.
      */
-    getTypeId() {
+    getTypeId(): number {
         return this._typeId;
     }
 
@@ -71,7 +81,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    setTypeId(typeId) {
+    setTypeId(typeId: number): EnumItem {
         ArgumentChecker.isInteger(typeId, 'typeId');
         this._typeId = typeId;
         return this;
@@ -83,7 +93,7 @@
      *
      * @return {number} - ordinal of the item in the Ignite enum type.
      */
-    getOrdinal() {
+    getOrdinal(): number {
         return this._ordinal;
     }
 
@@ -96,7 +106,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    setOrdinal(ordinal) {
+    setOrdinal(ordinal: number): EnumItem {
         ArgumentChecker.isInteger(ordinal, 'ordinal');
         this._ordinal = ordinal;
         return this;
@@ -108,7 +118,7 @@
      *
      * @return {string} - name of the item.
      */
-    getName() {
+    getName(): string {
         return this._name;
     }
 
@@ -121,7 +131,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    setName(name) {
+    setName(name: string): EnumItem {
         ArgumentChecker.notEmpty(name, 'name');
         this._name = name;
         return this;
@@ -133,7 +143,7 @@
      *
      * @return {number} - value of the item.
      */
-    getValue() {
+    getValue(): number {
         return this._value;
     }
 
@@ -146,7 +156,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    setValue(value) {
+    setValue(value: number): EnumItem {
         ArgumentChecker.isInteger(value, 'value');
         this._value = value;
         return this;
@@ -157,10 +167,10 @@
     /**
      * @ignore
      */
-    async _write(communicator, buffer) {
+    async _write(communicator: BinaryCommunicator, buffer: MessageBuffer) {
         const type = await this._getType(communicator, this._typeId);
-        if (!type || !type._isEnum) {
-            throw Errors.IgniteClientError.enumSerializationError(
+        if (!type || !type.isEnum) {
+            throw IgniteClientError.enumSerializationError(
                 true, Util.format('enum type id "%d" is not registered', this._typeId));
         }
         buffer.writeInteger(this._typeId);
@@ -169,44 +179,42 @@
             return;
         }
         else if (this._name !== null || this._value !== null) {
-            if (type._enumValues) {
-                for (let i = 0; i < type._enumValues.length; i++) {
-                    if (this._name === type._enumValues[i][0] ||
-                        this._value === type._enumValues[i][1]) {
+            if (type.enumValues) {
+                for (let i = 0; i < type.enumValues.length; i++) {
+                    if (this._name === type.enumValues[i][0] ||
+                        this._value === type.enumValues[i][1]) {
                         buffer.writeInteger(i);
                         return;
                     }
                 }
             }
         }
-        throw Errors.IgniteClientError.illegalArgumentError(
+        throw IgniteClientError.illegalArgumentError(
             'Proper ordinal, name or value must be specified for EnumItem');
     }
 
     /**
      * @ignore
      */
-    async _read(communicator, buffer) {
+    async _read(communicator: BinaryCommunicator, buffer: MessageBuffer) {
         this._typeId = buffer.readInteger();
         this._ordinal = buffer.readInteger();
         const type = await this._getType(communicator, this._typeId);
-        if (!type || !type._isEnum) {
-            throw Errors.IgniteClientError.enumSerializationError(
+        if (!type || !type.isEnum) {
+            throw IgniteClientError.enumSerializationError(
                 false, Util.format('enum type id "%d" is not registered', this._typeId));
         }
-        else if (!type._enumValues || type._enumValues.length <= this._ordinal) {
-            throw Errors.IgniteClientError.enumSerializationError(false, 'type mismatch');
+        else if (!type.enumValues || type.enumValues.length <= this._ordinal) {
+            throw IgniteClientError.enumSerializationError(false, 'type mismatch');
         }
-        this._name = type._enumValues[this._ordinal][0];
-        this._value = type._enumValues[this._ordinal][1];
+        this._name = type.enumValues[this._ordinal][0];
+        this._value = type.enumValues[this._ordinal][1];
     }
 
     /**
      * @ignore
      */
-    async _getType(communicator, typeId) {
+    async _getType(communicator: BinaryCommunicator, typeId: number) {
         return await communicator.typeStorage.getType(typeId);
     }
 }
-
-module.exports = EnumItem;
diff --git a/lib/Errors.js b/src/Errors.ts
similarity index 89%
rename from lib/Errors.js
rename to src/Errors.ts
index e7a1a9c..30ee6f6 100644
--- a/lib/Errors.js
+++ b/src/Errors.ts
@@ -22,7 +22,7 @@
 /**
  * Base Ignite client error class.
  */
-class IgniteClientError extends Error {
+export class IgniteClientError extends Error {
     constructor(message) {
         super(message);
     }
@@ -101,7 +101,7 @@
  * Ignite server returns error for the requested operation.
  * @extends IgniteClientError
  */
-class OperationError extends IgniteClientError {
+export class OperationError extends IgniteClientError {
     constructor(message) {
         super(message);
     }
@@ -111,7 +111,7 @@
  * Ignite client is not in an appropriate state for the requested operation.
  * @extends IgniteClientError
  */
-class IllegalStateError extends IgniteClientError {
+export class IllegalStateError extends IgniteClientError {
     constructor(state, message = null) {
         super(message || 'Ignite client is not in an appropriate state for the requested operation. Current state: ' + state);
     }
@@ -121,13 +121,8 @@
  * The requested operation is not completed due to the connection lost.
  * @extends IgniteClientError
  */
-class LostConnectionError extends IgniteClientError {
+export class LostConnectionError extends IgniteClientError {
     constructor(message = null) {
         super(message || 'Request is not completed due to the connection lost');
     }
 }
-
-module.exports.IgniteClientError = IgniteClientError;
-module.exports.OperationError = OperationError;
-module.exports.IllegalStateError = IllegalStateError;
-module.exports.LostConnectionError = LostConnectionError;
diff --git a/lib/IgniteClient.js b/src/IgniteClient.ts
similarity index 86%
rename from lib/IgniteClient.js
rename to src/IgniteClient.ts
index f897f95..7833a31 100644
--- a/lib/IgniteClient.js
+++ b/src/IgniteClient.ts
@@ -17,13 +17,16 @@
 
 'use strict';
 
-const CacheClient = require('./CacheClient');
-const IgniteClientConfiguration = require('./IgniteClientConfiguration');
-const CacheConfiguration = require('./CacheConfiguration');
-const BinaryUtils = require('./internal/BinaryUtils');
-const BinaryCommunicator = require('./internal/BinaryCommunicator');
-const ArgumentChecker = require('./internal/ArgumentChecker');
-const Logger = require('./internal/Logger');
+import BinaryCommunicator from "./internal/BinaryCommunicator";
+import ArgumentChecker from "./internal/ArgumentChecker";
+import Logger from "./internal/Logger";
+
+import Router from "./internal/Router";
+import {IgniteClientConfiguration} from "./IgniteClientConfiguration";
+import {CacheConfiguration} from "./CacheConfiguration";
+import { CacheClient } from "./CacheClient";
+import BinaryUtils from "./internal/BinaryUtils";
+import MessageBuffer from "./internal/MessageBuffer";
 
 /**
  * State of Ignite client.
@@ -45,28 +48,33 @@
  *     If connection with the Ignite node is lost, the client moves to CONNECTING state.
  *     If disconnect() method is called, the client moves to DISCONNECTED state.
  */
-const STATE = Object.freeze({
-    DISCONNECTED : 0,
-    CONNECTING : 1,
-    CONNECTED : 2
-});
+export enum STATE {
+    DISCONNECTED = 0,
+    CONNECTING = 1,
+    CONNECTED = 2
+}
+
+export type IgniteClientOnStateChanged = (state: STATE, reason: string) => void;
 
 /**
  * Class representing Ignite client.
  *
  */
-class IgniteClient {
+export class IgniteClient {
+
+    private _router: Router;
+
+    private _communicator: BinaryCommunicator;
 
     /**
      * Public constructor.
      *
-     * @param {IgniteClient.onStateChanged} [onStateChanged] -
-     * callback called everytime when the client has moved to a new state {@link IgniteClient.STATE}.
+     * @param {IgniteClientOnStateChanged} [onStateChanged] -
+     * callback called everytime when the client has moved to a new state {@link STATE}.
      *
      * @return {IgniteClient} - new IgniteClient instance.
      */
-    constructor(onStateChanged = null) {
-        const Router = require('./internal/Router');
+    constructor(onStateChanged: IgniteClientOnStateChanged = null) {
         this._router = new Router(onStateChanged);
         this._communicator = new BinaryCommunicator(this._router);
     }
@@ -76,13 +84,6 @@
     }
 
     /**
-     * onStateChanged callback.
-     * @callback IgniteClient.onStateChanged
-     * @param {IgniteClient.STATE} state - the new state of the client.
-     * @param {string} reason - the reason why the state has been changed.
-     */
-
-    /**
      * Connects the client.
      *
      * Should be called from DISCONNECTED state only.
@@ -95,7 +96,7 @@
      * @throws {IllegalStateError} if the client is not in DISCONNECTED {@link IgniteClient.STATE}.
      * @throws {IgniteClientError} if other error.
      */
-    async connect(config) {
+    async connect(config: IgniteClientConfiguration): Promise<void> {
         ArgumentChecker.notEmpty(config, 'config');
         ArgumentChecker.hasType(config, 'config', false, IgniteClientConfiguration);
         await this._router.connect(this._communicator, config);
@@ -155,7 +156,7 @@
      * @throws {IllegalStateError} if the client is not in CONNECTED {@link IgniteClient.STATE}.
      * @throws {IgniteClientError} if other error.
      */
-    async getOrCreateCache(name, cacheConfig = null) {
+    async getOrCreateCache(name, cacheConfig = null): Promise<CacheClient> {
         ArgumentChecker.notEmpty(name, 'name');
         ArgumentChecker.hasType(cacheConfig, 'cacheConfig', false, CacheConfiguration);
         await this._communicator.send(
@@ -246,7 +247,7 @@
      * @throws {IllegalStateError} if the client is not in CONNECTED {@link IgniteClient.STATE}.
      * @throws {IgniteClientError} if other error.
      */
-    async cacheNames() {
+    async cacheNames(): Promise<string[]> {
         let names;
         await this._communicator.send(
             BinaryUtils.OPERATION.CACHE_GET_NAMES,
@@ -272,14 +273,14 @@
     /**
      * @ignore
      */
-    _getCache(name, cacheConfig = null) {
+    _getCache(name: string, cacheConfig: CacheConfiguration = null) {
         return new CacheClient(name, cacheConfig, this._communicator);
     }
 
     /**
      * @ignore
      */
-    async _writeCacheNameOrConfig(buffer, name, cacheConfig) {
+    async _writeCacheNameOrConfig(buffer: MessageBuffer, name: string, cacheConfig: CacheConfiguration) {
         if (cacheConfig) {
             await cacheConfig._write(this._communicator, buffer, name);
         }
@@ -288,5 +289,3 @@
         }
     }
 }
-
-module.exports = IgniteClient;
diff --git a/lib/IgniteClientConfiguration.js b/src/IgniteClientConfiguration.ts
similarity index 76%
rename from lib/IgniteClientConfiguration.js
rename to src/IgniteClientConfiguration.ts
index 6c05b24..752cd21 100644
--- a/lib/IgniteClientConfiguration.js
+++ b/src/IgniteClientConfiguration.ts
@@ -17,10 +17,9 @@
 
 'use strict';
 
-const FS = require('fs');
-const Util = require('util');
-const Errors = require('./Errors');
-const ArgumentChecker = require('./internal/ArgumentChecker');
+import ArgumentChecker from "./internal/ArgumentChecker";
+import {NetConnectOpts} from "net";
+import {ConnectionOptions} from "tls";
 
 /**
  * Class representing Ignite client configuration.
@@ -31,7 +30,19 @@
  *   - (optional) TLS enabling
  *   - (optional) connection options
  */
-class IgniteClientConfiguration {
+export class IgniteClientConfiguration {
+
+    private _userName: string;
+
+    private _password: string;
+
+    private _useTLS: boolean;
+
+    private _partitionAwareness: boolean;
+
+    private _endpoints: string[];
+
+    private _options: NetConnectOpts | ConnectionOptions;
 
     /**
      * Creates an instance of Ignite client configuration
@@ -47,7 +58,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    constructor(...endpoints) {
+    constructor(...endpoints: string[]) {
         ArgumentChecker.notEmpty(endpoints, 'endpoints');
         this._endpoints = endpoints;
         this._userName = null;
@@ -69,7 +80,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    setUserName(userName) {
+    setUserName(userName: string): IgniteClientConfiguration {
         this._userName = userName;
         return this;
     }
@@ -86,7 +97,7 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    setPassword(password) {
+    setPassword(password: string): IgniteClientConfiguration {
         this._password = password;
         return this;
     }
@@ -105,12 +116,35 @@
      *
      * @return {IgniteClientConfiguration} - the same instance of the IgniteClientConfiguration.
      */
-    setConnectionOptions(useTLS, connectionOptions = null, partitionAwareness = false) {
+    setConnectionOptions(useTLS: boolean, connectionOptions: NetConnectOpts | ConnectionOptions = null, partitionAwareness: boolean = false) {
         this._useTLS = useTLS;
         this._options = connectionOptions;
         this._partitionAwareness = partitionAwareness;
         return this;
     }
-}
 
-module.exports = IgniteClientConfiguration;
+    get userName(): string {
+        return this._userName;
+    }
+
+    get password(): string {
+        return this._password;
+    }
+
+    get options(): NetConnectOpts | ConnectionOptions {
+        return this._options;
+    }
+
+    get partitionAwareness(): boolean {
+        return this._partitionAwareness;
+    }
+
+    get useTLS(): boolean {
+        return this._useTLS;
+    }
+
+    get endpoints(): string[] {
+        return this._endpoints;
+    }
+
+}
diff --git a/lib/ObjectType.js b/src/ObjectType.ts
similarity index 80%
rename from lib/ObjectType.js
rename to src/ObjectType.ts
index 00c4d56..8973a67 100644
--- a/lib/ObjectType.js
+++ b/src/ObjectType.ts
@@ -17,97 +17,12 @@
 
 'use strict';
 
-const Util = require('util');
-const Errors = require('./Errors');
-const ArgumentChecker = require('./internal/ArgumentChecker');
+import * as Util from "util";
+import ArgumentChecker from "./internal/ArgumentChecker";
+import { IgniteClientError } from "./Errors";
 
-/**
- * Supported Ignite type codes for primitive (simple) types.
- * @typedef ObjectType.PRIMITIVE_TYPE
- * @enum
- * @readonly
- * @property BYTE 1
- * @property SHORT 2
- * @property INTEGER 3
- * @property LONG 4
- * @property FLOAT 5
- * @property DOUBLE 6
- * @property CHAR 7
- * @property BOOLEAN 8
- * @property STRING 9
- * @property UUID 10
- * @property DATE 11
- * @property BYTE_ARRAY 12
- * @property SHORT_ARRAY 13
- * @property INTEGER_ARRAY 14
- * @property LONG_ARRAY 15
- * @property FLOAT_ARRAY 16
- * @property DOUBLE_ARRAY 17
- * @property CHAR_ARRAY 18
- * @property BOOLEAN_ARRAY 19
- * @property STRING_ARRAY 20
- * @property UUID_ARRAY 21
- * @property DATE_ARRAY 22
- * @property ENUM 28
- * @property ENUM_ARRAY 29
- * @property DECIMAL 30
- * @property DECIMAL_ARRAY 31
- * @property TIMESTAMP 33
- * @property TIMESTAMP_ARRAY 34
- * @property TIME 36
- * @property TIME_ARRAY 37
- */
-const PRIMITIVE_TYPE = Object.freeze({
-    BYTE : 1,
-    SHORT : 2,
-    INTEGER : 3,
-    LONG : 4,
-    FLOAT : 5,
-    DOUBLE : 6,
-    CHAR : 7,
-    BOOLEAN : 8,
-    STRING : 9,
-    UUID : 10,
-    DATE : 11,
-    BYTE_ARRAY : 12,
-    SHORT_ARRAY : 13,
-    INTEGER_ARRAY : 14,
-    LONG_ARRAY : 15,
-    FLOAT_ARRAY : 16,
-    DOUBLE_ARRAY : 17,
-    CHAR_ARRAY : 18,
-    BOOLEAN_ARRAY : 19,
-    STRING_ARRAY : 20,
-    UUID_ARRAY : 21,
-    DATE_ARRAY : 22,
-    ENUM : 28,
-    ENUM_ARRAY : 29,
-    DECIMAL : 30,
-    DECIMAL_ARRAY : 31,
-    TIMESTAMP : 33,
-    TIMESTAMP_ARRAY : 34,
-    TIME : 36,
-    TIME_ARRAY : 37
-});
-
-/**
- * Supported Ignite type codes for non-primitive (composite) types.
- * @typedef ObjectType.COMPOSITE_TYPE
- * @enum
- * @readonly
- * @property OBJECT_ARRAY 23
- * @property COLLECTION 24
- * @property MAP 25
- * @property NULL 101
- * @property COMPLEX_OBJECT 103
- */
-const COMPOSITE_TYPE = Object.freeze({
-    OBJECT_ARRAY : 23,
-    COLLECTION : 24,
-    MAP : 25,
-    NULL : 101,
-    COMPLEX_OBJECT : 103
-});
+import { PRIMITIVE_TYPE, COMPOSITE_TYPE } from "./internal/Constants";
+import BinaryUtils from "./internal/BinaryUtils";
 
 /**
  * Base class representing a type of Ignite object.
@@ -288,20 +203,26 @@
  * @hideconstructor
  */
 
-class ObjectType {
-    static get PRIMITIVE_TYPE() {
+export class ObjectType {
+
+    private _typeCode: number;
+
+    static get PRIMITIVE_TYPE(): typeof PRIMITIVE_TYPE {
         return PRIMITIVE_TYPE;
     }
 
-    static get COMPOSITE_TYPE() {
+    static get COMPOSITE_TYPE(): typeof COMPOSITE_TYPE {
         return COMPOSITE_TYPE;
     }
 
-    /** Private methods */
-
-    constructor(typeCode) {
+    constructor(typeCode: number) {
         this._typeCode = typeCode;
     }
+
+    get typeCode() {
+        return this._typeCode;
+    }
+
 }
 
 /**
@@ -312,7 +233,7 @@
  * @hideconstructor
  * @extends ObjectType
  */
-class CompositeType extends ObjectType {
+export class CompositeType extends ObjectType {
 }
 
 /**
@@ -323,10 +244,10 @@
  * @property HASH_MAP 1
  * @property LINKED_HASH_MAP 2
  */
-const MAP_SUBTYPE = Object.freeze({
-    HASH_MAP : 1,
-    LINKED_HASH_MAP : 2
-});
+export enum MAP_SUBTYPE {
+    HASH_MAP = 1,
+    LINKED_HASH_MAP = 2
+}
 
 /**
  * Class representing a map type of Ignite object.
@@ -336,7 +257,14 @@
  *
  * @extends CompositeType
  */
-class MapObjectType extends CompositeType {
+export class MapObjectType extends CompositeType {
+
+    private _subType: MAP_SUBTYPE;
+
+    private _keyType: PRIMITIVE_TYPE | CompositeType;
+
+    private _valueType: PRIMITIVE_TYPE | CompositeType;
+
     static get MAP_SUBTYPE() {
         return MAP_SUBTYPE;
     }
@@ -352,13 +280,13 @@
      * will try to make automatic mapping between JavaScript types and Ignite object types -
      * according to the mapping table defined in the description of the {@link ObjectType} class.
      *
-     * @param {MapObjectType.MAP_SUBTYPE} [mapSubType=MAP_SUBTYPE.HASH_MAP] - map subtype, one of the
-     *   {@link MapObjectType.MAP_SUBTYPE} constants.
-     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [keyType=null] - type of the keys in the map:
+     * @param {MAP_SUBTYPE} [mapSubType=MAP_SUBTYPE.HASH_MAP] - map subtype, one of the
+     *   {@link MAP_SUBTYPE} constants.
+     * @param {PRIMITIVE_TYPE | CompositeType} [keyType=null] - type of the keys in the map:
      *   - either a type code of primitive (simple) type
      *   - or an instance of class representing non-primitive (composite) type
      *   - or null (or not specified) that means the type is not specified
-     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [valueType=null] - type of the values in the map:
+     * @param {PRIMITIVE_TYPE | CompositeType} [valueType=null] - type of the values in the map:
      *   - either a type code of primitive (simple) type
      *   - or an instance of class representing non-primitive (composite) type
      *   - or null (or not specified) that means the type is not specified
@@ -367,9 +295,8 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    constructor(mapSubType = MapObjectType.MAP_SUBTYPE.HASH_MAP, keyType = null, valueType = null) {
+    constructor(mapSubType: MAP_SUBTYPE = MapObjectType.MAP_SUBTYPE.HASH_MAP, keyType: PRIMITIVE_TYPE | CompositeType = null, valueType: PRIMITIVE_TYPE | CompositeType = null) {
         super(COMPOSITE_TYPE.MAP);
-        const BinaryUtils = require('./internal/BinaryUtils');
         ArgumentChecker.hasValueFrom(mapSubType, 'mapSubType', false, MapObjectType.MAP_SUBTYPE);
         this._subType = mapSubType;
         BinaryUtils.checkObjectType(keyType, 'keyType');
@@ -392,15 +319,15 @@
  * @property LINKED_HASH_SET 4
  * @property SINGLETON_LIST 5
  */
-const COLLECTION_SUBTYPE = Object.freeze({
-    USER_SET : -1,
-    USER_COL : 0,
-    ARRAY_LIST : 1,
-    LINKED_LIST : 2,
-    HASH_SET : 3,
-    LINKED_HASH_SET : 4,
-    SINGLETON_LIST : 5
-});
+export enum COLLECTION_SUBTYPE {
+    USER_SET = -1,
+    USER_COL = 0,
+    ARRAY_LIST = 1,
+    LINKED_LIST = 2,
+    HASH_SET = 3,
+    LINKED_HASH_SET = 4,
+    SINGLETON_LIST = 5
+}
 
 /**
  * Class representing a collection type of Ignite object.
@@ -410,7 +337,12 @@
  *
  * @extends CompositeType
  */
-class CollectionObjectType extends CompositeType {
+export class CollectionObjectType extends CompositeType {
+
+    private _subType: COLLECTION_SUBTYPE;
+
+    private _elementType: PRIMITIVE_TYPE | CompositeType;
+
     static get COLLECTION_SUBTYPE() {
         return COLLECTION_SUBTYPE;
     }
@@ -425,9 +357,9 @@
      * will try to make automatic mapping between JavaScript types and Ignite object types -
      * according to the mapping table defined in the description of the {@link ObjectType} class.
      *
-     * @param {CollectionObjectType.COLLECTION_SUBTYPE} collectionSubType - collection subtype, one of the
-     *  {@link CollectionObjectType.COLLECTION_SUBTYPE} constants.
-     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [elementType=null] - type of elements in the collection:
+     * @param {COLLECTION_SUBTYPE} collectionSubType - collection subtype, one of the
+     *  {@link COLLECTION_SUBTYPE} constants.
+     * @param {PRIMITIVE_TYPE | CompositeType} [elementType=null] - type of elements in the collection:
      *   - either a type code of primitive (simple) type
      *   - or an instance of class representing non-primitive (composite) type
      *   - or null (or not specified) that means the type is not specified
@@ -436,9 +368,8 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    constructor(collectionSubType, elementType = null) {
+    constructor(collectionSubType: COLLECTION_SUBTYPE, elementType: PRIMITIVE_TYPE | CompositeType = null) {
         super(COMPOSITE_TYPE.COLLECTION);
-        const BinaryUtils = require('./internal/BinaryUtils');
         ArgumentChecker.hasValueFrom(
             collectionSubType, 'collectionSubType', false, CollectionObjectType.COLLECTION_SUBTYPE);
         this._subType = collectionSubType;
@@ -472,7 +403,8 @@
  *
  * @extends CompositeType
  */
-class ObjectArrayType extends CompositeType {
+export class ObjectArrayType extends CompositeType {
+    _elementType: PRIMITIVE_TYPE | CompositeType;
 
     /**
      * Public constructor.
@@ -483,7 +415,7 @@
      * will try to make automatic mapping between JavaScript types and Ignite object types -
      * according to the mapping table defined in the description of the {@link ObjectType} class.
      *
-     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [elementType=null] - type of the array element:
+     * @param {PRIMITIVE_TYPE | CompositeType} [elementType=null] - type of the array element:
      *   - either a type code of primitive (simple) type
      *   - or an instance of class representing non-primitive (composite) type
      *   - or null (or not specified) that means the type is not specified
@@ -492,9 +424,8 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    constructor(elementType = null) {
+    constructor(elementType: PRIMITIVE_TYPE | CompositeType = null) {
         super(COMPOSITE_TYPE.OBJECT_ARRAY);
-        const BinaryUtils = require('./internal/BinaryUtils');
         BinaryUtils.checkObjectType(elementType, 'elementType');
         this._elementType = elementType;
     }
@@ -508,7 +439,15 @@
  *
  * @extends CompositeType
  */
-class ComplexObjectType extends CompositeType {
+export class ComplexObjectType extends CompositeType {
+
+    private _template: object;
+
+    private _objectConstructor: Function;
+
+    private _typeName: string;
+
+    private _fields: Map<string, any>;
 
     /**
      * Public constructor.
@@ -547,8 +486,7 @@
             typeName = this._objectConstructor.name;
         }
         this._typeName = typeName;
-        this._fields = new Map();
-        const BinaryUtils = require('./internal/BinaryUtils');
+        this._fields = new Map<string, any>();
         for (let fieldName of BinaryUtils.getJsObjectFieldNames(this._template)) {
             this._fields.set(fieldName, null);
         }
@@ -573,10 +511,9 @@
      */
     setFieldType(fieldName, fieldType) {
         if (!this._fields.has(fieldName)) {
-            throw Errors.IgniteClientError.illegalArgumentError(
+            throw IgniteClientError.illegalArgumentError(
                 Util.format('Field "%s" is absent in the complex object type', fieldName));
         }
-        const BinaryUtils = require('./internal/BinaryUtils');
         BinaryUtils.checkObjectType(fieldType, 'fieldType');
         this._fields.set(fieldName, fieldType);
         return this;
@@ -590,11 +527,9 @@
     _getFieldType(fieldName) {
         return this._fields.get(fieldName);
     }
-}
 
-module.exports.ObjectType = ObjectType;
-module.exports.CompositeType = CompositeType;
-module.exports.MapObjectType = MapObjectType;
-module.exports.CollectionObjectType = CollectionObjectType;
-module.exports.ComplexObjectType = ComplexObjectType;
-module.exports.ObjectArrayType = ObjectArrayType;
+    get typeName() {
+        return this._typeName;
+    }
+
+}
diff --git a/lib/Query.js b/src/Query.ts
similarity index 78%
rename from lib/Query.js
rename to src/Query.ts
index d3f6f87..e8f7ee1 100644
--- a/lib/Query.js
+++ b/src/Query.ts
@@ -17,14 +17,20 @@
 
 'use strict';
 
-const Cursor = require('./Cursor').Cursor;
-const SqlFieldsCursor = require('./Cursor').SqlFieldsCursor;
-const ArgumentChecker = require('./internal/ArgumentChecker');
-const BinaryCommunicator = require('./internal/BinaryCommunicator');
-const BinaryUtils = require('./internal/BinaryUtils');
+import * as Util from "util";
+import {BaseCursor, Cursor, SqlFieldsCursor} from "./Cursor";
+import ArgumentChecker from "./internal/ArgumentChecker";
+import BinaryCommunicator from "./internal/BinaryCommunicator";
+import BinaryUtils, {OPERATION} from "./internal/BinaryUtils";
+import { CompositeType } from "./ObjectType";
+import { PRIMITIVE_TYPE } from "./internal/Constants";
+import MessageBuffer from "./internal/MessageBuffer";
+import {CacheEntry} from "./CacheClient";
 
 const PAGE_SIZE_DEFAULT = 1024;
 
+const DeprecateSetLocal = Util.deprecate(() => {}, "Query.setLocal is deprecated. It will be removed in later versions.");
+
 /**
  * Base class representing an Ignite SQL or Scan query.
  *
@@ -32,7 +38,13 @@
  *
  * @hideconstructor
  */
-class Query {
+abstract class Query<T> {
+
+    protected _local: boolean;
+
+    protected _pageSize: number;
+
+    protected _operation: OPERATION;
 
     /**
      * Set local query flag.
@@ -41,7 +53,8 @@
      *
      * @return {Query} - the same instance of the Query.
      */
-    setLocal(local) {
+    setLocal(local: boolean): Query<T> {
+        DeprecateSetLocal();
         this._local = local;
         return this;
     }
@@ -53,7 +66,7 @@
      *
      * @return {Query} - the same instance of the Query.
      */
-    setPageSize(pageSize) {
+    setPageSize(pageSize: number): Query<T> {
         this._pageSize = pageSize;
         return this;
     }
@@ -63,18 +76,34 @@
     /**
      * @ignore
      */
-    constructor(operation) {
+    constructor(operation: OPERATION) {
         this._operation = operation;
         this._local = false;
         this._pageSize = PAGE_SIZE_DEFAULT;
     }
+
+    abstract _getCursor(communicator, payload, keyType, valueType): Promise<BaseCursor<T>>;
 }
 
 /**
  * Class representing an SQL query which returns the whole cache entries (key-value pairs).
  * @extends Query
  */
-class SqlQuery extends Query {
+export class SqlQuery extends Query<CacheEntry> {
+
+    private _type: string;
+
+    protected _sql: string;
+
+    private _argTypes: (PRIMITIVE_TYPE | CompositeType)[];
+
+    protected _distributedJoins: boolean;
+
+    protected _replicatedOnly: boolean;
+
+    protected _timeout: number;
+
+    private _args: object[];
 
     /**
      * Public constructor.
@@ -97,7 +126,7 @@
      *
      * @return {SqlQuery} - new SqlQuery instance.
      */
-    constructor(type, sql) {
+    constructor(type: string, sql: string) {
         super(BinaryUtils.OPERATION.QUERY_SQL);
         this.setType(type);
         this.setSql(sql);
@@ -115,7 +144,7 @@
      *
      * @return {SqlQuery} - the same instance of the SqlQuery.
      */
-    setType(type) {
+    setType(type: string): SqlQuery {
         if (this instanceof SqlFieldsQuery) {
             ArgumentChecker.invalidArgument(type, 'type', SqlFieldsQuery);
         }
@@ -133,7 +162,7 @@
      *
      * @return {SqlQuery} - the same instance of the SqlQuery.
      */
-    setSql(sql) {
+    setSql(sql: string): SqlQuery {
         ArgumentChecker.notNull(sql, 'sql');
         this._sql = sql;
         return this;
@@ -151,7 +180,7 @@
      *
      * @return {SqlQuery} - the same instance of the SqlQuery.
      */
-    setArgs(...args) {
+    setArgs(...args: object[]): SqlQuery {
         this._args = args;
         return this;
     }
@@ -173,7 +202,7 @@
      *
      * @return {SqlQuery} - the same instance of the SqlQuery.
      */
-    setArgTypes(...argTypes) {
+    setArgTypes(...argTypes: (PRIMITIVE_TYPE | CompositeType)[]): SqlQuery {
         this._argTypes = argTypes;
         return this;
     }
@@ -185,7 +214,7 @@
      *
      * @return {SqlQuery} - the same instance of the SqlQuery.
      */
-    setDistributedJoins(distributedJoins) {
+    setDistributedJoins(distributedJoins: boolean): SqlQuery {
         this._distributedJoins = distributedJoins;
         return this;
     }
@@ -197,7 +226,7 @@
      *
      * @return {SqlQuery} - the same instance of the SqlQuery.
      */
-    setReplicatedOnly(replicatedOnly) {
+    setReplicatedOnly(replicatedOnly: boolean): SqlQuery {
         this._replicatedOnly = replicatedOnly;
         return this;
     }
@@ -210,7 +239,7 @@
      *
      * @return {SqlQuery} - the same instance of the SqlQuery.
      */
-    setTimeout(timeout) {
+    setTimeout(timeout: number): SqlQuery {
         this._timeout = timeout;
         return this;
     }
@@ -220,7 +249,7 @@
     /**
      * @ignore
      */
-    async _write(communicator, buffer) {
+    async _write(communicator: BinaryCommunicator, buffer: MessageBuffer) {
         BinaryCommunicator.writeString(buffer, this._type);
         BinaryCommunicator.writeString(buffer, this._sql);
         await this._writeArgs(communicator, buffer);
@@ -234,7 +263,7 @@
     /**
      * @ignore
      */
-    async _writeArgs(communicator, buffer) {
+    async _writeArgs(communicator: BinaryCommunicator, buffer: MessageBuffer) {
         const argsLength = this._args ? this._args.length : 0;
         buffer.writeInteger(argsLength);
         if (argsLength > 0) {
@@ -249,7 +278,7 @@
     /**
      * @ignore
      */
-    async _getCursor(communicator, payload, keyType = null, valueType = null) {
+    async _getCursor(communicator, payload, keyType = null, valueType = null): Promise<BaseCursor<CacheEntry>> {
         const cursor = new Cursor(communicator, BinaryUtils.OPERATION.QUERY_SQL_CURSOR_GET_PAGE, payload, keyType, valueType);
         cursor._readId(payload);
         return cursor;
@@ -265,18 +294,32 @@
  * @property SELECT 1
  * @property UPDATE 2
  */
-const STATEMENT_TYPE = Object.freeze({
-    ANY : 0,
-    SELECT : 1,
-    UPDATE : 2
-});
+export enum STATEMENT_TYPE {
+    ANY = 0,
+    SELECT = 1,
+    UPDATE = 2
+}
 
 
 /**
  * Class representing an SQL Fields query.
  * @extends SqlQuery
  */
-class SqlFieldsQuery extends SqlQuery {
+export class SqlFieldsQuery extends SqlQuery {
+
+    private _schema: string;
+
+    private _maxRows: number;
+
+    private _statementType: STATEMENT_TYPE;
+
+    private _enforceJoinOrder: boolean;
+
+    private _collocated: boolean;
+
+    private _lazy: boolean;
+
+    private _includeFieldNames: boolean;
 
     /**
      * Public constructor.
@@ -305,12 +348,12 @@
      *
      * @return {SqlFieldsQuery} - new SqlFieldsQuery instance.
      */
-    constructor(sql) {
+    constructor(sql: string) {
         super(null, sql);
-        this._operation = BinaryUtils.OPERATION.QUERY_SQL_FIELDS;
+        this._operation = OPERATION.QUERY_SQL_FIELDS;
         this._schema = null;
         this._maxRows = -1;
-        this._statementType = SqlFieldsQuery.STATEMENT_TYPE.ANY;
+        this._statementType = STATEMENT_TYPE.ANY;
         this._enforceJoinOrder = false;
         this._collocated = false;
         this._lazy = false;
@@ -328,7 +371,7 @@
      *
      * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
      */
-    setSchema(schema) {
+    setSchema(schema: string): SqlFieldsQuery {
         this._schema = schema;
         return this;
     }
@@ -340,7 +383,7 @@
      *
      * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
      */
-    setMaxRows(maxRows) {
+    setMaxRows(maxRows: number): SqlFieldsQuery {
         this._maxRows = maxRows;
         return this;
     }
@@ -348,11 +391,11 @@
     /**
      * Set statement type.
      *
-     * @param {SqlFieldsQuery.STATEMENT_TYPE} type - statement type.
+     * @param {STATEMENT_TYPE} type - statement type.
      *
      * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
      */
-    setStatementType(type) {
+    setStatementType(type: STATEMENT_TYPE): SqlFieldsQuery {
         this._statementType = type;
         return this;
     }
@@ -364,7 +407,7 @@
      *
      * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
      */
-    setEnforceJoinOrder(enforceJoinOrder) {
+    setEnforceJoinOrder(enforceJoinOrder: boolean): SqlFieldsQuery {
         this._enforceJoinOrder = enforceJoinOrder;
         return this;
     }
@@ -376,7 +419,7 @@
      *
      * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
      */
-    setCollocated(collocated) {
+    setCollocated(collocated: boolean): SqlFieldsQuery {
         this._collocated = collocated;
         return this;
     }
@@ -388,7 +431,7 @@
      *
      * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
      */
-    setLazy(lazy) {
+    setLazy(lazy: boolean): SqlFieldsQuery {
         this._lazy = lazy;
         return this;
     }
@@ -400,7 +443,7 @@
      *
      * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
      */
-    setIncludeFieldNames(includeFieldNames) {
+    setIncludeFieldNames(includeFieldNames: boolean): SqlFieldsQuery {
         this._includeFieldNames = includeFieldNames;
         return this;
     }
@@ -427,10 +470,12 @@
         buffer.writeBoolean(this._includeFieldNames);
     }
 
+    // noinspection JSAnnotator
     /**
      * @ignore
      */
-    async _getCursor(communicator, payload, keyType = null, valueType = null) {
+    // @ts-ignore
+    async _getCursor(communicator, payload, keyType = null, valueType = null): Promise<BaseCursor<Array<object>>> {
         const cursor = new SqlFieldsCursor(communicator, payload);
         await cursor._readFieldNames(payload, this._includeFieldNames);
         return cursor;
@@ -444,7 +489,9 @@
  * The query returns all entries from the entire cache or from the specified partition.
  * @extends Query
  */
-class ScanQuery extends Query {
+export class ScanQuery extends Query<CacheEntry> {
+
+    private _partitionNumber: number;
 
     /**
      * Public constructor.
@@ -462,7 +509,7 @@
      * @return {ScanQuery} - new ScanQuery instance.
      */
     constructor() {
-        super(BinaryUtils.OPERATION.QUERY_SCAN);
+        super(OPERATION.QUERY_SCAN);
         this._partitionNumber = -1;
     }
 
@@ -475,7 +522,7 @@
      *
      * @return {ScanQuery} - the same instance of the ScanQuery.
      */
-    setPartitionNumber(partitionNumber) {
+    setPartitionNumber(partitionNumber: number): ScanQuery {
         this._partitionNumber = partitionNumber;
         return this;
     }
@@ -485,7 +532,7 @@
     /**
      * @ignore
      */
-    async _write(communicator, buffer) {
+    async _write(communicator: BinaryCommunicator, buffer: MessageBuffer) {
         // filter
         await communicator.writeObject(buffer, null);
         buffer.writeInteger(this._pageSize);
@@ -496,13 +543,9 @@
     /**
      * @ignore
      */
-    async _getCursor(communicator, payload, keyType = null, valueType = null) {
-        const cursor = new Cursor(communicator, BinaryUtils.OPERATION.QUERY_SCAN_CURSOR_GET_PAGE, payload, keyType, valueType);
+    async _getCursor(communicator: BinaryCommunicator, payload, keyType = null, valueType = null) {
+        const cursor = new Cursor(communicator, OPERATION.QUERY_SCAN_CURSOR_GET_PAGE, payload, keyType, valueType);
         cursor._readId(payload);
         return cursor;
     }
 }
-
-module.exports.SqlQuery = SqlQuery;
-module.exports.SqlFieldsQuery = SqlFieldsQuery;
-module.exports.ScanQuery = ScanQuery;
diff --git a/lib/Timestamp.js b/src/Timestamp.ts
similarity index 92%
rename from lib/Timestamp.js
rename to src/Timestamp.ts
index 04d750c..f255306 100644
--- a/lib/Timestamp.js
+++ b/src/Timestamp.ts
@@ -17,7 +17,7 @@
 
 'use strict';
 
-const ArgumentChecker = require('./internal/ArgumentChecker');
+import ArgumentChecker from "./internal/ArgumentChecker";
 
 /**
  * Class representing an Ignite timestamp type.
@@ -29,7 +29,9 @@
  *     this class specifies additional methods to operate with the nanoseconds.
  * @extends Date
  */
-class Timestamp extends Date {
+export class Timestamp extends Date {
+
+    private _nanos: number;
 
     /**
      * Public constructor.
@@ -52,7 +54,7 @@
      *
      * @return {number} - nanoseconds of the last millisecond.
      */
-    getNanos() {
+    getNanos(): number {
         return this._nanos;
     }
 
@@ -66,11 +68,9 @@
      *
      * @throws {IgniteClientError} if error.
      */
-    setNanos(nanos) {
+    setNanos(nanos: number): Timestamp {
         ArgumentChecker.isInteger(nanos, 'nanos');
         this._nanos = nanos;
         return this;
     }
 }
-
-module.exports = Timestamp;
diff --git a/lib/internal/Logger.js b/src/index.ts
similarity index 60%
copy from lib/internal/Logger.js
copy to src/index.ts
index 628c70e..7c57cc1 100644
--- a/lib/internal/Logger.js
+++ b/src/index.ts
@@ -17,29 +17,21 @@
 
 'use strict';
 
-/** Utility class for logging errors and debug messages. */
-class Logger {
-    static get debug() {
-        return Logger._debug;
-    }
+export * from "./Timestamp";
+export * from './ObjectType';
+export * from './BinaryObject';
 
-    static set debug(value) {
-        Logger._debug = value;
-    }
+export * from './EnumItem';
+const d = require('decimal.js').default;
+const l = require('long');
+export const Decimal = d;
+export const Long = l;
+export * from './IgniteClientConfiguration';
+export * from './CacheClient';
+export * from './CacheClient';
+export * from './CacheConfiguration';
+export * from './Query';
+export * from './Cursor';
+export * as Errors from  "./Errors";
 
-    static logDebug(data, ...args) {
-        if (Logger._debug) {
-            console.log(data, ...args);
-        }
-    }
-
-    static logError(data, ...args) {
-        if (Logger._debug) {
-            console.log('ERROR: ' + data, ...args);
-        }
-    }
-}
-
-Logger._debug = false;
-
-module.exports = Logger;
+export {IgniteClient} from './IgniteClient';
\ No newline at end of file
diff --git a/lib/internal/ArgumentChecker.js b/src/internal/ArgumentChecker.ts
similarity index 72%
rename from lib/internal/ArgumentChecker.js
rename to src/internal/ArgumentChecker.ts
index 9e60ad6..3bc5585 100644
--- a/lib/internal/ArgumentChecker.js
+++ b/src/internal/ArgumentChecker.ts
@@ -17,20 +17,20 @@
 
 'use strict';
 
-const Util = require('util');
-const Errors = require('../Errors');
+import * as Util from 'util';
+import {IgniteClientError} from "../Errors";
 
 /** Helper class for the library methods arguments check. */
-class ArgumentChecker {
+export default class ArgumentChecker {
     static notEmpty(arg, argName) {
         if (!arg || arg instanceof Array && arg.length === 0) {
-            throw Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument should not be empty', argName));
+            throw IgniteClientError.illegalArgumentError(Util.format('"%s" argument should not be empty', argName));
         }
     }
 
     static notNull(arg, argName) {
         if (arg === null || arg === undefined) {
-            throw Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument should not be null', argName));
+            throw IgniteClientError.illegalArgumentError(Util.format('"%s" argument should not be null', argName));
         }
     }
 
@@ -49,7 +49,7 @@
                     return;
                 }
             }
-            throw Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument has incorrect type', argName));
+            throw IgniteClientError.illegalArgumentError(Util.format('"%s" argument has incorrect type', argName));
         }
     }
 
@@ -61,23 +61,21 @@
         }
         else {
             if (!Object.values(values).includes(arg)) {
-                throw Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument has incorrect value', argName));
+                throw IgniteClientError.illegalArgumentError(Util.format('"%s" argument has incorrect value', argName));
             }
         }
     }
 
     static isInteger(arg, argName) {
         if (arg === null || arg === undefined || !Number.isInteger(arg)) {
-            throw Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument should be integer', argName));
+            throw IgniteClientError.illegalArgumentError(Util.format('"%s" argument should be integer', argName));
         }
     }
 
     static invalidArgument(arg, argName, type) {
         if (arg !== null && arg !== undefined) {
-            throw Errors.IgniteClientError.illegalArgumentError(
+            throw IgniteClientError.illegalArgumentError(
                 Util.format('"%s" argument is invalid for %s', argName, type.constructor.name));
         }
     }
 }
-
-module.exports = ArgumentChecker;
diff --git a/lib/internal/BinaryCommunicator.js b/src/internal/BinaryCommunicator.ts
similarity index 91%
rename from lib/internal/BinaryCommunicator.js
rename to src/internal/BinaryCommunicator.ts
index 6c5d839..f9f1b37 100644
--- a/lib/internal/BinaryCommunicator.js
+++ b/src/internal/BinaryCommunicator.ts
@@ -17,23 +17,31 @@
 
 'use strict';
 
-const Decimal = require('decimal.js');
-const CollectionObjectType = require('../ObjectType').CollectionObjectType;
-const ComplexObjectType = require('../ObjectType').ComplexObjectType;
-const Errors = require('../Errors');
-const Timestamp = require('../Timestamp');
-const EnumItem = require('../EnumItem');
-const BinaryUtils = require('./BinaryUtils');
-const BinaryTypeStorage = require('./BinaryTypeStorage');
+import {CollectionObjectType, ComplexObjectType} from "../ObjectType";
+import {Timestamp} from "../Timestamp";
+import {EnumItem} from "../EnumItem";
+import BinaryUtils from "./BinaryUtils";
+import BinaryTypeStorage from "./BinaryTypeStorage";
+import { IgniteClientError } from "../Errors";
+import {BinaryObject} from "../BinaryObject";
+import BinaryType from "./BinaryType";
+import Router from './Router';
+import MessageBuffer from "./MessageBuffer";
+import { AffinityHint } from "../CacheClient";
+const Decimal = require('decimal.js').default;
 
-class BinaryCommunicator {
+export default class BinaryCommunicator {
 
-    constructor(router) {
+    private _router: Router;
+
+    private _typeStorage: BinaryTypeStorage;
+
+    constructor(router: Router) {
         this._router = router;
         this._typeStorage = new BinaryTypeStorage(this);
     }
 
-    static readString(buffer) {
+    static readString(buffer: MessageBuffer): string | null {
         const typeCode = buffer.readByte();
         BinaryUtils.checkTypesComatibility(BinaryUtils.TYPE_CODE.STRING, typeCode);
         if (typeCode === BinaryUtils.TYPE_CODE.NULL) {
@@ -42,7 +50,7 @@
         return buffer.readString();
     }
 
-    static writeString(buffer, value) {
+    static writeString(buffer: MessageBuffer, value: string) {
         if (value === null) {
             buffer.writeByte(BinaryUtils.TYPE_CODE.NULL);
         }
@@ -52,7 +60,7 @@
         }
     }
 
-    async send(opCode, payloadWriter, payloadReader = null, affinityHint = null) {
+    async send(opCode, payloadWriter, payloadReader = null, affinityHint: AffinityHint = null) {
         await this._router.send(opCode, payloadWriter, payloadReader, affinityHint);
     }
 
@@ -152,7 +160,7 @@
                 await this._writeComplexObject(buffer, object, objectType);
                 break;
             default:
-                throw Errors.IgniteClientError.unsupportedTypeError(objectType);
+                throw IgniteClientError.unsupportedTypeError(objectType);
         }
     }
 
@@ -213,7 +221,7 @@
             case BinaryUtils.TYPE_CODE.COMPLEX_OBJECT:
                 return await this._readComplexObject(buffer, expectedType);
             default:
-                throw Errors.IgniteClientError.unsupportedTypeError(objectTypeCode);
+                throw IgniteClientError.unsupportedTypeError(objectTypeCode);
         }
     }
 
@@ -279,12 +287,12 @@
         const size = buffer.readInteger();
         const subType = buffer.readByte();
         const isSet = CollectionObjectType._isSet(subType);
-        const result = isSet ? new Set() : new Array(size);
+        const result: Set<any> | Array<any> = isSet ? new Set() : new Array(size);
         let element;
         for (let i = 0; i < size; i++) {
             element = await this.readObject(buffer, expectedColType ? expectedColType._elementType : null);
             if (isSet) {
-                result.add(element);
+                (result as Set<any>).add(element);
             }
             else {
                 result[i] = element;
@@ -307,7 +315,6 @@
 
     async _readComplexObject(buffer, expectedType) {
         buffer.position = buffer.position - 1;
-        const BinaryObject = require('../BinaryObject');
         const binaryObject = await BinaryObject._fromBuffer(this, buffer);
         return expectedType ?
             await binaryObject.toObject(expectedType) : binaryObject;
@@ -365,12 +372,11 @@
     }
 
     async _writeArray(buffer, array, arrayType, arrayTypeCode) {
-        const BinaryType = require('./BinaryType');
         const elementType = BinaryUtils.getArrayElementType(arrayType);
         const keepElementType = BinaryUtils.keepArrayElementType(arrayTypeCode);
         if (arrayTypeCode === BinaryUtils.TYPE_CODE.OBJECT_ARRAY) {
             buffer.writeInteger(elementType instanceof ComplexObjectType ?
-                BinaryType._calculateId(elementType._typeName) : -1);
+                BinaryType._calculateId((elementType as ComplexObjectType).typeName) : -1);
         }
         buffer.writeInteger(array.length);
         for (let elem of array) {
@@ -401,9 +407,6 @@
     }
 
     async _writeComplexObject(buffer, object, objectType) {
-        const BinaryObject = require('../BinaryObject');
         await this._writeBinaryObject(buffer, await BinaryObject.fromObject(object, objectType));
     }
 }
-
-module.exports = BinaryCommunicator;
diff --git a/lib/internal/BinaryType.js b/src/internal/BinaryType.ts
similarity index 84%
rename from lib/internal/BinaryType.js
rename to src/internal/BinaryType.ts
index bba5f93..cb649f4 100644
--- a/lib/internal/BinaryType.js
+++ b/src/internal/BinaryType.ts
@@ -17,20 +17,28 @@
 
 'use strict';
 
-const Util = require('util');
-const Long = require('long');
-const ComplexObjectType = require('../ObjectType').ComplexObjectType;
-const BinaryTypeStorage = require('./BinaryTypeStorage');
-const BinaryUtils = require('./BinaryUtils');
-const BinaryCommunicator = require('./BinaryCommunicator');
-const Errors = require('../Errors');
+import * as Util from "util";
+import * as Long from "long";
+import {ComplexObjectType} from "../ObjectType";
+import BinaryTypeStorage from "./BinaryTypeStorage";
+import BinaryUtils from "./BinaryUtils";
+import BinaryCommunicator from "./BinaryCommunicator";
+import {IgniteClientError} from "../Errors";
 
-class BinaryType {
-    constructor(name) {
+export default class BinaryType {
+
+    private _id: number;
+    private _fields: Map<number, BinaryField>;
+    private _schemas: Map<number, BinarySchema>;
+    private _name: string;
+    private _isEnum: boolean;
+    private _enumValues: [string, number][];
+
+    constructor(name: string) {
         this._name = name;
         this._id = BinaryType._calculateId(name);
-        this._fields = new Map();
-        this._schemas = new Map();
+        this._fields = new Map<number, BinaryField>();
+        this._schemas = new Map<number, BinarySchema>();
         this._isEnum = false;
         this._enumValues = null;
     }
@@ -39,6 +47,10 @@
         return this._id;
     }
 
+    set id(val: number) {
+        this._id = val;
+    }
+
     get name() {
         return this._name;
     }
@@ -55,25 +67,25 @@
         return this._fields.has(fieldId);
     }
 
-    removeField(fieldId) {
+    removeField(fieldId: number) {
         return this._fields.delete(fieldId);
     }
 
-    setField(field) {
+    setField(field: BinaryField) {
         this._fields.set(field.id, field);
     }
 
-    hasSchema(schemaId) {
+    hasSchema(schemaId: number) {
         return this._schemas.has(schemaId);
     }
 
-    addSchema(schema) {
+    addSchema(schema: BinarySchema) {
         if (!this.hasSchema(schema.id)) {
             this._schemas.set(schema.id, schema);
         }
     }
 
-    getSchema(schemaId) {
+    getSchema(schemaId: number) {
         return this._schemas.get(schemaId);
     }
 
@@ -83,9 +95,8 @@
             fieldId = field.id;
             if (this.hasField(fieldId)) {
                 if (this.getField(fieldId).typeCode !== field.typeCode) {
-                    throw Errors.IgniteClientError.serializationError(
-                        true, Util.format('type conflict for field "%s" of complex object type "%s"'),
-                        field.name, this._name);
+                    throw IgniteClientError.serializationError(
+                        true, Util.format('type conflict for field "%s" of complex object type "%s"', field.name, this._name));
                 }
             }
             else {
@@ -96,8 +107,7 @@
     }
 
     clone() {
-        const result = new BinaryType();
-        result._name = this._name;
+        const result = new BinaryType(this._name);
         result._id = this._id;
         result._fields = new Map(this._fields.entries());
         result._schemas = new Map(this._schemas.entries());
@@ -114,7 +124,15 @@
         return this._name !== null;
     }
 
-    static _calculateId(name) {
+    get enumValues(): [string, number][] {
+        return this._enumValues;
+    }
+
+    get isEnum(): boolean {
+        return this._isEnum;
+    }
+
+    static _calculateId(name): number {
         return BinaryUtils.strHashCodeLowerCase(name);
     }
 
@@ -185,7 +203,7 @@
         this._isEnum = buffer.readBoolean();
         if (this._isEnum) {
             const valuesCount = buffer.readInteger();
-            this._enumValues = new Array(valuesCount);
+            this._enumValues = new Array<[string, number]>(valuesCount);
             for (let i = 0; i < valuesCount; i++) {
                 this._enumValues[i] = [BinaryCommunicator.readString(buffer), buffer.readInteger()];
             }
@@ -198,10 +216,13 @@
 /** FNV1 hash prime. */
 const FNV1_PRIME = 0x01000193;
 
-class BinarySchema {
+export class BinarySchema {
+    private _id: number;
+    private _fieldIds: Set<number>;
+    private _isValid: boolean;
     constructor() {
         this._id = BinarySchema._schemaInitialId();
-        this._fieldIds = new Set();
+        this._fieldIds = new Set<number>();
         this._isValid = true;
     }
 
@@ -250,7 +271,7 @@
         return this._fieldIds.has(fieldId);
     }
 
-    static _schemaInitialId() {
+    static _schemaInitialId(): number {
         return FNV1_OFFSET_BASIS | 0;
     }
 
@@ -292,8 +313,11 @@
     }
 }
 
-class BinaryField {
-    constructor(name, typeCode) {
+export class BinaryField {
+    private _name: string;
+    private _id: number;
+    private _typeCode: number;
+    constructor(name: string, typeCode: number) {
         this._name = name;
         this._id = BinaryField._calculateId(name);
         this._typeCode = typeCode;
@@ -338,7 +362,10 @@
     }
 }
 
-class BinaryTypeBuilder {
+export class BinaryTypeBuilder {
+    private _schema: BinarySchema;
+    private _type: BinaryType;
+    private _fromStorage: boolean;
 
     static fromTypeName(typeName) {
         let result = new BinaryTypeBuilder();
@@ -346,7 +373,7 @@
         return result;
     }
 
-    static async fromTypeId(communicator, typeId, schemaId) {
+    static async fromTypeId(communicator: BinaryCommunicator, typeId: number, schemaId: number) {
         let result = new BinaryTypeBuilder();
         let type = await communicator.typeStorage.getType(typeId, schemaId);
         if (type) {
@@ -354,7 +381,7 @@
             if (schemaId !== null) {
                 result._schema = type.getSchema(schemaId);
                 if (!result._schema) {
-                    throw Errors.IgniteClientError.serializationError(
+                    throw IgniteClientError.serializationError(
                         false, Util.format('schema id "%d" specified for complex object of type "%s" not found',
                             schemaId, type.name));
                 }
@@ -366,7 +393,7 @@
             return result;
         }
         result._init(null);
-        result._type._id = typeId;
+        result._type.id = typeId;
         return result;
     }
 
@@ -381,7 +408,7 @@
         }
     }
 
-    static fromComplexObjectType(complexObjectType, jsObject) {
+    static fromComplexObjectType(complexObjectType: ComplexObjectType, jsObject: object) {
         let result = new BinaryTypeBuilder();
         const typeInfo = BinaryTypeStorage.getByComplexObjectType(complexObjectType);
         if (typeInfo) {
@@ -413,7 +440,11 @@
     }
 
     getField(fieldId) {
-        return this._type._fields.get(fieldId);
+        return this._type.getField(fieldId);
+    }
+
+    get schema() {
+        return this._schema;
     }
 
     setField(fieldName, fieldTypeCode = null) {
@@ -477,7 +508,3 @@
         }
     }
 }
-
-module.exports = BinaryType;
-module.exports.BinaryField = BinaryField;
-module.exports.BinaryTypeBuilder = BinaryTypeBuilder;
diff --git a/lib/internal/BinaryTypeStorage.js b/src/internal/BinaryTypeStorage.ts
similarity index 73%
rename from lib/internal/BinaryTypeStorage.js
rename to src/internal/BinaryTypeStorage.ts
index 2248eb5..42a98e8 100644
--- a/lib/internal/BinaryTypeStorage.js
+++ b/src/internal/BinaryTypeStorage.ts
@@ -17,22 +17,29 @@
 
 'use strict';
 
-const Errors = require('../Errors');
-const BinaryUtils = require('./BinaryUtils');
-const Util = require('util');
+import BinaryUtils from "./BinaryUtils";
+import * as Util from "util";
+import { IgniteClientError } from "../Errors";
+import BinaryType, { BinarySchema } from "./BinaryType";
+import BinaryCommunicator from "./BinaryCommunicator";
+import {ComplexObjectType} from "../ObjectType";
 
-class BinaryTypeStorage {
+export default class BinaryTypeStorage {
+
+    private _communicator: BinaryCommunicator;
+    private _types: Map<number, BinaryType>;
+    private static _complexObjectTypes: Map<ComplexObjectType, [BinaryType, BinarySchema]>;
 
     constructor(communicator) {
         this._communicator = communicator;
-        this._types = new Map();
+        this._types = new Map<number, BinaryType>();
     }
 
-    static getByComplexObjectType(complexObjectType) {
+    static getByComplexObjectType(complexObjectType: ComplexObjectType) {
         return BinaryTypeStorage.complexObjectTypes.get(complexObjectType);
     }
 
-    static setByComplexObjectType(complexObjectType, type, schema) {
+    static setByComplexObjectType(complexObjectType: ComplexObjectType, type: BinaryType, schema: BinarySchema) {
         if (!BinaryTypeStorage.complexObjectTypes.has(complexObjectType)) {
             BinaryTypeStorage.complexObjectTypes.set(complexObjectType, [type, schema]);
         }
@@ -40,12 +47,12 @@
 
     static get complexObjectTypes() {
         if (!BinaryTypeStorage._complexObjectTypes) {
-            BinaryTypeStorage._complexObjectTypes = new Map();
+            BinaryTypeStorage._complexObjectTypes = new Map<ComplexObjectType, [BinaryType, BinarySchema]>();
         }
         return BinaryTypeStorage._complexObjectTypes;
     }
 
-    async addType(binaryType, binarySchema) {
+    async addType(binaryType: BinaryType, binarySchema: BinarySchema) {
         const typeId = binaryType.id;
         const schemaId = binarySchema.id;
         let storageType = this._types.get(typeId);
@@ -62,7 +69,7 @@
         }
     }
 
-    async getType(typeId, schemaId = null) {
+    async getType(typeId: number, schemaId = null): Promise<BinaryType> {
         let storageType = this._types.get(typeId);
         if (!storageType || schemaId && !storageType.hasSchema(schemaId)) {
             storageType = await this._getBinaryType(typeId);
@@ -75,10 +82,9 @@
 
     /** Private methods */
 
-    async _getBinaryType(typeId) {
-        const BinaryType = require('./BinaryType');
+    async _getBinaryType(typeId: number) {
         let binaryType = new BinaryType(null);
-        binaryType._id = typeId;
+        binaryType.id = typeId;
         await this._communicator.send(
             BinaryUtils.OPERATION.GET_BINARY_TYPE,
             async (payload) => {
@@ -98,7 +104,7 @@
 
     async _putBinaryType(binaryType) {
         if (!binaryType.isValid()) {
-            throw Errors.IgniteClientError.serializationError(
+            throw IgniteClientError.serializationError(
                 true, Util.format('type "%d" can not be registered', binaryType.id));
         }
         await this._communicator.send(
@@ -108,5 +114,3 @@
             });
     }
 }
-
-module.exports = BinaryTypeStorage;
diff --git a/lib/internal/BinaryUtils.js b/src/internal/BinaryUtils.ts
similarity index 79%
rename from lib/internal/BinaryUtils.js
rename to src/internal/BinaryUtils.ts
index 0822bb4..a602da5 100644
--- a/lib/internal/BinaryUtils.js
+++ b/src/internal/BinaryUtils.ts
@@ -17,73 +17,76 @@
 
 'use strict';
 
-const Decimal = require('decimal.js');
-const Long = require('long');
-const ObjectType = require('../ObjectType').ObjectType;
-const CompositeType = require('../ObjectType').CompositeType;
-const MapObjectType = require('../ObjectType').MapObjectType;
-const CollectionObjectType = require('../ObjectType').CollectionObjectType;
-const ComplexObjectType = require('../ObjectType').ComplexObjectType;
-const ObjectArrayType = require('../ObjectType').ObjectArrayType;
-const Timestamp = require('../Timestamp');
-const EnumItem = require('../EnumItem');
-const Errors = require('../Errors');
-const ArgumentChecker = require('./ArgumentChecker');
+import {
+    CollectionObjectType,
+    ComplexObjectType,
+    CompositeType,
+    MapObjectType,
+    ObjectArrayType,
+    ObjectType
+} from "../ObjectType";
+import {Timestamp} from "../Timestamp";
+import {EnumItem} from "../EnumItem";
+const Decimal = require('decimal.js').default;
+import ArgumentChecker from "./ArgumentChecker";
+import { IgniteClientError } from "../Errors";
+import { PRIMITIVE_TYPE, COMPOSITE_TYPE } from "./Constants";
+import {BinaryObject} from "../BinaryObject";
+import * as Long from "long";
 
 // Operation codes
-const OPERATION = Object.freeze({
+export enum OPERATION {
     // Key-Value Queries
-    CACHE_GET : 1000,
-    CACHE_PUT : 1001,
-    CACHE_PUT_IF_ABSENT : 1002,
-    CACHE_GET_ALL : 1003,
-    CACHE_PUT_ALL : 1004,
-    CACHE_GET_AND_PUT : 1005,
-    CACHE_GET_AND_REPLACE : 1006,
-    CACHE_GET_AND_REMOVE : 1007,
-    CACHE_GET_AND_PUT_IF_ABSENT : 1008,
-    CACHE_REPLACE : 1009,
-    CACHE_REPLACE_IF_EQUALS : 1010,
-    CACHE_CONTAINS_KEY : 1011,
-    CACHE_CONTAINS_KEYS : 1012,
-    CACHE_CLEAR : 1013,
-    CACHE_CLEAR_KEY : 1014,
-    CACHE_CLEAR_KEYS : 1015,
-    CACHE_REMOVE_KEY : 1016,
-    CACHE_REMOVE_IF_EQUALS : 1017,
-    CACHE_REMOVE_KEYS : 1018,
-    CACHE_REMOVE_ALL : 1019,
-    CACHE_GET_SIZE : 1020,
-    CACHE_LOCAL_PEEK  : 1021,
+    CACHE_GET = 1000,
+    CACHE_PUT = 1001,
+    CACHE_PUT_IF_ABSENT = 1002,
+    CACHE_GET_ALL = 1003,
+    CACHE_PUT_ALL = 1004,
+    CACHE_GET_AND_PUT = 1005,
+    CACHE_GET_AND_REPLACE = 1006,
+    CACHE_GET_AND_REMOVE = 1007,
+    CACHE_GET_AND_PUT_IF_ABSENT = 1008,
+    CACHE_REPLACE = 1009,
+    CACHE_REPLACE_IF_EQUALS = 1010,
+    CACHE_CONTAINS_KEY = 1011,
+    CACHE_CONTAINS_KEYS = 1012,
+    CACHE_CLEAR = 1013,
+    CACHE_CLEAR_KEY = 1014,
+    CACHE_CLEAR_KEYS = 1015,
+    CACHE_REMOVE_KEY = 1016,
+    CACHE_REMOVE_IF_EQUALS = 1017,
+    CACHE_REMOVE_KEYS = 1018,
+    CACHE_REMOVE_ALL = 1019,
+    CACHE_GET_SIZE = 1020,
+    CACHE_LOCAL_PEEK  = 1021,
     // Cache Configuration
-    CACHE_GET_NAMES : 1050,
-    CACHE_CREATE_WITH_NAME : 1051,
-    CACHE_GET_OR_CREATE_WITH_NAME : 1052,
-    CACHE_CREATE_WITH_CONFIGURATION : 1053,
-    CACHE_GET_OR_CREATE_WITH_CONFIGURATION : 1054,
-    CACHE_GET_CONFIGURATION : 1055,
-    CACHE_DESTROY : 1056,
-    CACHE_PARTITIONS : 1101,
+    CACHE_GET_NAMES = 1050,
+    CACHE_CREATE_WITH_NAME = 1051,
+    CACHE_GET_OR_CREATE_WITH_NAME = 1052,
+    CACHE_CREATE_WITH_CONFIGURATION = 1053,
+    CACHE_GET_OR_CREATE_WITH_CONFIGURATION = 1054,
+    CACHE_GET_CONFIGURATION = 1055,
+    CACHE_DESTROY = 1056,
+    CACHE_PARTITIONS = 1101,
     // SQL and Scan Queries
-    QUERY_SCAN : 2000,
-    QUERY_SCAN_CURSOR_GET_PAGE : 2001,
-    QUERY_SQL : 2002,
-    QUERY_SQL_CURSOR_GET_PAGE : 2003,
-    QUERY_SQL_FIELDS : 2004,
-    QUERY_SQL_FIELDS_CURSOR_GET_PAGE : 2005,
-    RESOURCE_CLOSE : 0,
+    QUERY_SCAN = 2000,
+    QUERY_SCAN_CURSOR_GET_PAGE = 2001,
+    QUERY_SQL = 2002,
+    QUERY_SQL_CURSOR_GET_PAGE = 2003,
+    QUERY_SQL_FIELDS = 2004,
+    QUERY_SQL_FIELDS_CURSOR_GET_PAGE = 2005,
+    RESOURCE_CLOSE = 0,
     // Binary Types
-    GET_BINARY_TYPE : 3002,
-    PUT_BINARY_TYPE : 3003
-});
+    GET_BINARY_TYPE = 3002,
+    PUT_BINARY_TYPE = 3003
+}
 
-const TYPE_CODE = Object.assign({
-        BINARY_OBJECT : 27,
-        BINARY_ENUM : 38
-    },
-    ObjectType.PRIMITIVE_TYPE,
-    ObjectType.COMPOSITE_TYPE);
-
+export const TYPE_CODE = {
+    ...PRIMITIVE_TYPE,
+    ...COMPOSITE_TYPE,
+    BINARY_OBJECT: 27,
+    BINARY_ENUM: 38
+}
 
 const TYPE_INFO = Object.freeze({
     [TYPE_CODE.BYTE] : {
@@ -260,7 +263,7 @@
 
 const UTF8_ENCODING = 'utf8';
 
-class BinaryUtils {
+export default class BinaryUtils {
     static get OPERATION() {
         return OPERATION;
     }
@@ -278,7 +281,7 @@
         return size ? size : 0;
     }
 
-    static get ENCODING() {
+    static get ENCODING(): BufferEncoding {
         return UTF8_ENCODING;
     }
 
@@ -294,8 +297,8 @@
         return TYPE_INFO[BinaryUtils.getTypeCode(type)].NULLABLE === true;
     }
 
-    static getTypeCode(type) {
-        return type instanceof CompositeType ? type._typeCode : type;
+    static getTypeCode(type: PRIMITIVE_TYPE | CompositeType): number {
+        return type instanceof CompositeType ? type.typeCode : type;
     }
 
     static checkObjectType(type, argName) {
@@ -305,11 +308,10 @@
         ArgumentChecker.hasValueFrom(type, argName, false, ObjectType.PRIMITIVE_TYPE);
     }
 
-    static calcObjectType(object) {
-        const BinaryObject = require('../BinaryObject');
+    static calcObjectType(object): PRIMITIVE_TYPE | CompositeType {
         const objectType = typeof object;
         if (object === null) {
-            throw Errors.IgniteClientError.unsupportedTypeError(BinaryUtils.TYPE_CODE.NULL);
+            throw IgniteClientError.unsupportedTypeError(BinaryUtils.TYPE_CODE.NULL);
         }
         else if (objectType === 'number') {
             return BinaryUtils.TYPE_CODE.DOUBLE;
@@ -349,7 +351,7 @@
         else if (objectType === 'object') {
             return new ComplexObjectType(object);
         }
-        throw Errors.IgniteClientError.unsupportedTypeError(objectType);
+        throw IgniteClientError.unsupportedTypeError(objectType);
     }
 
     static checkCompatibility(value, type) {
@@ -359,7 +361,7 @@
         const typeCode = BinaryUtils.getTypeCode(type);
         if (value === null) {
             if (!BinaryUtils.isNullable(typeCode)) {
-                throw Errors.IgniteClientError.typeCastError(BinaryUtils.TYPE_CODE.NULL, typeCode);
+                throw IgniteClientError.typeCastError(BinaryUtils.TYPE_CODE.NULL, typeCode);
             }
             return;
         }
@@ -369,7 +371,7 @@
         }
         const valueTypeCode = BinaryUtils.getTypeCode(BinaryUtils.calcObjectType(value));
         if (typeCode !== valueTypeCode) {
-            throw Errors.IgniteClientError.typeCastError(valueTypeCode, typeCode);
+            throw IgniteClientError.typeCastError(valueTypeCode, typeCode);
         }
     }
 
@@ -386,61 +388,61 @@
             case BinaryUtils.TYPE_CODE.INTEGER:
             case BinaryUtils.TYPE_CODE.LONG:
                 if (!Number.isInteger(value)) {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.FLOAT:
             case BinaryUtils.TYPE_CODE.DOUBLE:
                 if (valueType !== 'number') {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.CHAR:
                 if (valueType !== 'string' || value.length !== 1) {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.BOOLEAN:
                 if (valueType !== 'boolean') {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.STRING:
                 if (valueType !== 'string') {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.UUID:
-                if (!value instanceof Array ||
+                if (!(value instanceof Array) ||
                     value.length !== BinaryUtils.getSize(BinaryUtils.TYPE_CODE.UUID)) {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 value.forEach(element =>
                     BinaryUtils.checkStandardTypeCompatibility(element, BinaryUtils.TYPE_CODE.BYTE));
                 return;
             case BinaryUtils.TYPE_CODE.DATE:
-                if (!value instanceof Date) {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                if (!(value instanceof Date)) {
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.ENUM:
-                if (!value instanceof EnumItem) {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                if (!(value instanceof EnumItem)) {
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.DECIMAL:
-                if (!value instanceof Decimal) {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                if (!(value instanceof Decimal)) {
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.TIMESTAMP:
-                if (!value instanceof Timestamp) {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                if (!(value instanceof Timestamp)) {
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.TIME:
-                if (!value instanceof Date) {
-                    throw Errors.IgniteClientError.valueCastError(value, typeCode);
+                if (!(value instanceof Date)) {
+                    throw IgniteClientError.valueCastError(value, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.BYTE_ARRAY:
@@ -459,29 +461,29 @@
             case BinaryUtils.TYPE_CODE.DECIMAL_ARRAY:
             case BinaryUtils.TYPE_CODE.TIMESTAMP_ARRAY:
             case BinaryUtils.TYPE_CODE.TIME_ARRAY:
-                if (!value instanceof Array) {
-                    throw Errors.IgniteClientError.typeCastError(valueType, typeCode);
+                if (!(value instanceof Array)) {
+                    throw IgniteClientError.typeCastError(valueType, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.MAP:
-                if (!value instanceof Map) {
-                    throw Errors.IgniteClientError.typeCastError(valueType, typeCode);
+                if (!(value instanceof Map)) {
+                    throw IgniteClientError.typeCastError(valueType, typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.COLLECTION:
                 if (!(type && type._isSet() && value instanceof Set || value instanceof Array)) {
-                    throw Errors.IgniteClientError.typeCastError(valueType, type && type._isSet() ? 'set' : typeCode);
+                    throw IgniteClientError.typeCastError(valueType, type && type._isSet() ? 'set' : typeCode);
                 }
                 return;
             case BinaryUtils.TYPE_CODE.NULL:
                 if (value !== null) {
-                    throw Errors.IgniteClientError.typeCastError('not null', typeCode);
+                    throw IgniteClientError.typeCastError('not null', typeCode);
                 }
                 return;
             default:
                 const valueTypeCode = BinaryUtils.getTypeCode(BinaryUtils.calcObjectType(value));
                 if (valueTypeCode === BinaryUtils.TYPE_CODE.BINARY_OBJECT) {
-                    throw Errors.IgniteClientError.typeCastError(valueTypeCode, typeCode);
+                    throw IgniteClientError.typeCastError(valueTypeCode, typeCode);
                 }
                 return;
         }
@@ -505,20 +507,20 @@
             return;
         }
         else if (actualTypeCode !== expectedTypeCode) {
-            throw Errors.IgniteClientError.typeCastError(actualTypeCode, expectedTypeCode);
+            throw IgniteClientError.typeCastError(actualTypeCode, expectedTypeCode);
         }
     }
 
-    static getArrayElementType(arrayType) {
+    static getArrayElementType(arrayType): PRIMITIVE_TYPE | COMPOSITE_TYPE | CompositeType {
         if (arrayType instanceof ObjectArrayType) {
             return arrayType._elementType;
         }
         else if (arrayType === BinaryUtils.TYPE_CODE.OBJECT_ARRAY) {
             return null;
         }
-        const elementTypeCode = TYPE_INFO[arrayType].ELEMENT_TYPE;
+        const elementTypeCode: PRIMITIVE_TYPE | COMPOSITE_TYPE = TYPE_INFO[arrayType].ELEMENT_TYPE;
         if (!elementTypeCode) {
-            throw Errors.IgniteClientError.internalError();
+            throw IgniteClientError.internalError();
         }
         return elementTypeCode;
     }
@@ -567,7 +569,7 @@
     }
 
     static getJsObjectFieldNames(jsObject) {
-        var fields = new Array();
+        var fields = [];
         for (let field in jsObject) {
             if (typeof jsObject[field] !== 'function') {
                 fields.push(field);
@@ -633,7 +635,7 @@
         return hash;
     }
 
-    static strHashCode(str) {
+    static strHashCode(str): number {
         // This method calcuates hash code for the String Ignite type
         // bool must be a js 'string'
         let hash = 0, char;
@@ -647,7 +649,7 @@
         return hash;
     }
 
-    static strHashCodeLowerCase(str) {
+    static strHashCodeLowerCase(str): number {
         return BinaryUtils.strHashCode(str ? str.toLowerCase() : str);
     }
 
@@ -721,6 +723,4 @@
         // date must be an instance of Date or Timestamp
         return BinaryUtils.longHashCode(date.getTime());
     }
-}
-
-module.exports = BinaryUtils;
+}
\ No newline at end of file
diff --git a/lib/internal/ClientSocket.js b/src/internal/ClientSocket.ts
similarity index 78%
rename from lib/internal/ClientSocket.js
rename to src/internal/ClientSocket.ts
index 8efa5d0..e9a1074 100644
--- a/lib/internal/ClientSocket.js
+++ b/src/internal/ClientSocket.ts
@@ -17,19 +17,21 @@
 
 'use strict';
 
-const net = require('net');
-const tls = require('tls');
-const URL = require('url');
+import * as tls from 'tls';
+import * as net from 'net';
 const Long = require('long');
-const Util = require('util');
-const Errors = require('../Errors');
-const IgniteClientConfiguration = require('../IgniteClientConfiguration');
-const MessageBuffer = require('./MessageBuffer');
-const BinaryUtils = require('./BinaryUtils');
-const BinaryCommunicator = require('./BinaryCommunicator');
-const PartitionAwarenessUtils = require('./PartitionAwarenessUtils');
-const ArgumentChecker = require('./ArgumentChecker');
-const Logger = require('./Logger');
+import * as Util from 'util';
+import BinaryUtils from "./BinaryUtils";
+
+import Logger from "./Logger";
+import ArgumentChecker from "./ArgumentChecker";
+import BinaryCommunicator from "./BinaryCommunicator";
+import MessageBuffer from "./MessageBuffer";
+import {NetConnectOpts, Socket } from "net";
+import { LostConnectionError, OperationError, IllegalStateError, IgniteClientError } from '../Errors';
+import { AffinityTopologyVersion } from './PartitionAwarenessUtils';
+import { IgniteClientConfiguration } from "../IgniteClientConfiguration";
+import { ConnectionOptions } from 'tls';
 
 const HANDSHAKE_SUCCESS_STATUS_CODE = 1;
 const REQUEST_SUCCESS_STATUS_CODE = 0;
@@ -39,6 +41,12 @@
 
 class ProtocolVersion {
 
+    private _major: number;
+
+    private _minor: number;
+
+    private _patch: number;
+
     constructor(major = null, minor = null, patch = null) {
         this._major = major;
         this._minor = minor;
@@ -94,16 +102,42 @@
 
 const CURRENT_VERSION = PROTOCOL_VERSION_1_4_0;
 
-const STATE = Object.freeze({
-    INITIAL : 0,
-    HANDSHAKE : 1,
-    CONNECTED : 2,
-    DISCONNECTED : 3
-});
+export enum STATE {
+    INITIAL = 0,
+    HANDSHAKE = 1,
+    CONNECTED = 2,
+    DISCONNECTED = 3
+}
 
-class ClientSocket {
+export default class ClientSocket {
 
-    constructor(endpoint, config, communicator, onSocketDisconnect, onAffinityTopologyChange) {
+    private _socket: Socket;
+
+    private _host: string;
+
+    private _buffer: MessageBuffer;
+
+    private _requests: Map<string, Request>;
+
+    private _nodeUuid: string;
+
+    private _error: string | Error;
+
+    private _endpoint: string;
+    private _config: IgniteClientConfiguration;
+    private _communicator: BinaryCommunicator;
+    private _onSocketDisconnect: Function;
+    private _onAffinityTopologyChange: Function;
+    private _state: STATE;
+    private _requestId: Long;
+    private _offset: number;
+    private _wasConnected: boolean;
+    private _handshakeRequestId: Long;
+    private _protocolVersion: ProtocolVersion;
+    private _port: number | string;
+    private _version: number;
+
+    constructor(endpoint: string, config: IgniteClientConfiguration, communicator: BinaryCommunicator, onSocketDisconnect: Function, onAffinityTopologyChange: Function) {
         ArgumentChecker.notEmpty(endpoint, 'endpoints');
         this._endpoint = endpoint;
         this._parseEndpoint(endpoint);
@@ -113,7 +147,7 @@
         this._onAffinityTopologyChange = onAffinityTopologyChange;
 
         this._state = STATE.INITIAL;
-        this._requests = new Map();
+        this._requests = new Map<string, Request>();
         this._requestId = Long.ZERO;
         this._handshakeRequestId = null;
         this._protocolVersion = null;
@@ -160,7 +194,7 @@
             });
         }
         else {
-            throw new Errors.IllegalStateError(this._state);
+            throw new IllegalStateError(this._state);
         }
     }
 
@@ -171,18 +205,18 @@
             await this._sendRequest(handshakeRequest);
         };
 
-        const options = Object.assign({},
-            this._config._options,
+        const options: (NetConnectOpts | ConnectionOptions) = Object.assign({},
+            this._config.options,
             { host : this._host, port : this._port, version : this._version });
 
-        if (this._config._useTLS) {
-            this._socket = tls.connect(options, onConnected);
+        if (this._config.useTLS) {
+            this._socket = tls.connect(<ConnectionOptions>options, onConnected);
         }
         else {
-            this._socket = net.createConnection(options, onConnected);
+            this._socket = net.createConnection(<NetConnectOpts>options, onConnected);
         }
 
-        this._socket.on('data', async (data) => {
+        this._socket.on('data', async (data: Buffer) => {
             try {
                 await this._processResponse(data);
             }
@@ -201,23 +235,23 @@
         });
     }
 
-    _addRequest(request) {
+    _addRequest(request: Request) {
         this._requests.set(request.id.toString(), request);
     }
 
-    async _sendRequest(request) {
+    async _sendRequest(request: Request) {
         try {
             const message = await request.getMessage();
             this._logMessage(request.id.toString(), true, message);
             this._socket.write(message);
         }
         catch (err) {
-            this._requests.delete(request.id);
+            this._requests.delete(request.id.toString());
             request.reject(err);
         }
     }
 
-    async _processResponse(message) {
+    async _processResponse(message: Buffer) {
         if (this._state === STATE.DISCONNECTED) {
             return;
         }
@@ -259,7 +293,6 @@
                 this._offset = 0;
             }
 
-
             if (this._requests.has(requestId)) {
                 const request = this._requests.get(requestId);
                 this._requests.delete(requestId);
@@ -271,12 +304,12 @@
                 }
             }
             else {
-                throw Errors.IgniteClientError.internalError('Invalid response id: ' + requestId);
+                throw IgniteClientError.internalError('Invalid response id: ' + requestId);
             }
         }
     }
 
-    async _finalizeHandshake(buffer, request) {
+    async _finalizeHandshake(buffer: MessageBuffer, request: Request) {
         const isSuccess = buffer.readByte() === HANDSHAKE_SUCCESS_STATUS_CODE;
 
         if (!isSuccess) {
@@ -288,8 +321,8 @@
 
             if (!this._protocolVersion.equals(serverVersion)) {
                 if (!this._isSupportedVersion(serverVersion) ||
-                    serverVersion.compareTo(PROTOCOL_VERSION_1_1_0) < 0 && this._config._userName) {
-                    request.reject(new Errors.OperationError(
+                    serverVersion.compareTo(PROTOCOL_VERSION_1_1_0) < 0 && this._config.userName) {
+                    request.reject(new OperationError(
                         Util.format('Protocol version mismatch: client %s / server %s. Server details: %s',
                             this._protocolVersion.toString(), serverVersion.toString(), errMessage)));
                     this._disconnect();
@@ -301,7 +334,7 @@
                 }
             }
             else {
-                request.reject(new Errors.OperationError(errMessage));
+                request.reject(new OperationError(errMessage));
                 this._disconnect();
             }
         }
@@ -316,7 +349,7 @@
         }
     }
 
-    async _finalizeResponse(buffer, request) {
+    async _finalizeResponse(buffer: MessageBuffer, request: Request) {
         let statusCode, isSuccess;
 
         if (this._protocolVersion.compareTo(PROTOCOL_VERSION_1_4_0) < 0) {
@@ -330,7 +363,7 @@
             isSuccess = !(flags & FLAG_ERROR);
 
             if (flags & FLAG_TOPOLOGY_CHANGED) {
-                const newVersion = new PartitionAwarenessUtils.AffinityTopologyVersion(buffer);
+                const newVersion = new AffinityTopologyVersion(buffer);
                 await this._onAffinityTopologyChange(newVersion);
             }
 
@@ -342,7 +375,7 @@
         if (!isSuccess) {
             // Error message
             const errMessage = BinaryCommunicator.readString(buffer);
-            request.reject(new Errors.OperationError(errMessage));
+            request.reject(new OperationError(errMessage));
         }
         else {
             try {
@@ -364,13 +397,13 @@
         this._protocolVersion.write(payload);
         // Client code
         payload.writeByte(2);
-        if (this._config._userName) {
-            BinaryCommunicator.writeString(payload, this._config._userName);
-            BinaryCommunicator.writeString(payload, this._config._password);
+        if (this._config.userName) {
+            BinaryCommunicator.writeString(payload, this._config.userName);
+            BinaryCommunicator.writeString(payload, this._config.password);
         }
     }
 
-    _getHandshake(version, resolve, reject) {
+    _getHandshake(version: ProtocolVersion, resolve: Function, reject: Function) {
         this._protocolVersion = version;
         const handshakeRequest = new Request(
             this.requestId, null, this._handshakePayloadWriter.bind(this), null, resolve, reject);
@@ -391,7 +424,7 @@
     _disconnect(close = true, callOnDisconnect = true) {
         this._state = STATE.DISCONNECTED;
         this._requests.forEach((request, id) => {
-            request.reject(new Errors.LostConnectionError(this._error));
+            request.reject(new LostConnectionError(this._error));
             this._requests.delete(id);
         });
         if (this._wasConnected && callOnDisconnect && this._onSocketDisconnect) {
@@ -421,7 +454,7 @@
                     this._host = this._host.substring(1, this._host.length - 1);
                 }
                 else {
-                    throw Errors.IgniteClientError.illegalArgumentError('Incorrect endpoint format: ' + endpoint);
+                    throw IgniteClientError.illegalArgumentError('Incorrect endpoint format: ' + endpoint);
                 }
             }
         }
@@ -438,9 +471,9 @@
             this._port = PORT_DEFAULT;
         }
         else {
-            this._port = parseInt(this._port);
+            this._port = parseInt(<string>this._port);
             if (isNaN(this._port)) {
-                throw Errors.IgniteClientError.illegalArgumentError('Incorrect endpoint format: ' + endpoint);
+                throw IgniteClientError.illegalArgumentError('Incorrect endpoint format: ' + endpoint);
             }
         }
     }
@@ -454,7 +487,13 @@
 }
 
 class Request {
-    constructor(id, opCode, payloadWriter, payloadReader, resolve, reject) {
+    private _id: Long;
+    private _resolve: Function;
+    private _reject: Function;
+    private _payloadWriter: Function;
+    private _opCode: number;
+    private _payloadReader: Function;
+    constructor(id: Long, opCode, payloadWriter, payloadReader, resolve: Function, reject: Function) {
         this._id = id;
         this._opCode = opCode;
         this._payloadWriter = payloadWriter;
@@ -463,7 +502,7 @@
         this._reject = reject;
     }
 
-    get id() {
+    get id(): Long {
         return this._id;
     }
 
@@ -500,5 +539,3 @@
         return message.data;
     }
 }
-
-module.exports = ClientSocket;
diff --git a/src/internal/Constants.ts b/src/internal/Constants.ts
new file mode 100644
index 0000000..f20f76b
--- /dev/null
+++ b/src/internal/Constants.ts
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+
+import exp = require("constants");
+
+/**
+ * Supported Ignite type codes for primitive (simple) types.
+ * @typedef ObjectType.PRIMITIVE_TYPE
+ * @enum
+ * @readonly
+ * @property BYTE 1
+ * @property SHORT 2
+ * @property INTEGER 3
+ * @property LONG 4
+ * @property FLOAT 5
+ * @property DOUBLE 6
+ * @property CHAR 7
+ * @property BOOLEAN 8
+ * @property STRING 9
+ * @property UUID 10
+ * @property DATE 11
+ * @property BYTE_ARRAY 12
+ * @property SHORT_ARRAY 13
+ * @property INTEGER_ARRAY 14
+ * @property LONG_ARRAY 15
+ * @property FLOAT_ARRAY 16
+ * @property DOUBLE_ARRAY 17
+ * @property CHAR_ARRAY 18
+ * @property BOOLEAN_ARRAY 19
+ * @property STRING_ARRAY 20
+ * @property UUID_ARRAY 21
+ * @property DATE_ARRAY 22
+ * @property ENUM 28
+ * @property ENUM_ARRAY 29
+ * @property DECIMAL 30
+ * @property DECIMAL_ARRAY 31
+ * @property TIMESTAMP 33
+ * @property TIMESTAMP_ARRAY 34
+ * @property TIME 36
+ * @property TIME_ARRAY 37
+ */
+export enum PRIMITIVE_TYPE {
+    BYTE = 1,
+    SHORT = 2,
+    INTEGER = 3,
+    LONG = 4,
+    FLOAT = 5,
+    DOUBLE = 6,
+    CHAR = 7,
+    BOOLEAN = 8,
+    STRING = 9,
+    UUID = 10,
+    DATE = 11,
+    BYTE_ARRAY = 12,
+    SHORT_ARRAY = 13,
+    INTEGER_ARRAY = 14,
+    LONG_ARRAY = 15,
+    FLOAT_ARRAY = 16,
+    DOUBLE_ARRAY = 17,
+    CHAR_ARRAY = 18,
+    BOOLEAN_ARRAY = 19,
+    STRING_ARRAY = 20,
+    UUID_ARRAY = 21,
+    DATE_ARRAY = 22,
+    ENUM = 28,
+    ENUM_ARRAY = 29,
+    DECIMAL = 30,
+    DECIMAL_ARRAY = 31,
+    TIMESTAMP = 33,
+    TIMESTAMP_ARRAY = 34,
+    TIME = 36,
+    TIME_ARRAY = 37
+}
+
+/**
+ * Supported Ignite type codes for non-primitive (composite) types.
+ * @typedef ObjectType.COMPOSITE_TYPE
+ * @enum
+ * @readonly
+ * @property OBJECT_ARRAY 23
+ * @property COLLECTION 24
+ * @property MAP 25
+ * @property NULL 101
+ * @property COMPLEX_OBJECT 103
+ */
+export enum COMPOSITE_TYPE {
+    OBJECT_ARRAY = 23,
+    COLLECTION = 24,
+    MAP = 25,
+    NULL = 101,
+    COMPLEX_OBJECT = 103
+}
\ No newline at end of file
diff --git a/lib/internal/Logger.js b/src/internal/Logger.ts
similarity index 81%
rename from lib/internal/Logger.js
rename to src/internal/Logger.ts
index 628c70e..f4b3d4b 100644
--- a/lib/internal/Logger.js
+++ b/src/internal/Logger.ts
@@ -18,28 +18,27 @@
 'use strict';
 
 /** Utility class for logging errors and debug messages. */
-class Logger {
-    static get debug() {
+export default class Logger {
+
+    private static _debug: boolean = false;
+
+    static get debug(): boolean {
         return Logger._debug;
     }
 
-    static set debug(value) {
+    static set debug(value: boolean) {
         Logger._debug = value;
     }
 
-    static logDebug(data, ...args) {
+    static logDebug(data: string, ...args: any[]) {
         if (Logger._debug) {
             console.log(data, ...args);
         }
     }
 
-    static logError(data, ...args) {
+    static logError(data: string, ...args: any[]) {
         if (Logger._debug) {
             console.log('ERROR: ' + data, ...args);
         }
     }
 }
-
-Logger._debug = false;
-
-module.exports = Logger;
diff --git a/lib/internal/MessageBuffer.js b/src/internal/MessageBuffer.ts
similarity index 85%
rename from lib/internal/MessageBuffer.js
rename to src/internal/MessageBuffer.ts
index ff13c4a..0e16783 100644
--- a/lib/internal/MessageBuffer.js
+++ b/src/internal/MessageBuffer.ts
@@ -18,14 +18,23 @@
 'use strict';
 
 const Long = require('long');
-const BinaryUtils = require('./BinaryUtils');
-const Errors = require('../Errors');
+import BinaryUtils from "./BinaryUtils";
+import { IgniteClientError } from '../Errors';
 
 const BUFFER_CAPACITY_DEFAULT = 256;
 const BYTE_ZERO = 0;
 const BYTE_ONE = 1;
 
-class MessageBuffer {
+export default class MessageBuffer {
+
+    private _buffer: Buffer;
+
+    private _capacity: number;
+
+    private _length: number;
+
+    private _position: number;
+
     constructor(capacity = BUFFER_CAPACITY_DEFAULT) {
         this._buffer = Buffer.allocUnsafe(capacity);
         this._capacity = capacity;
@@ -33,7 +42,7 @@
         this._position = 0;
     }
 
-    static from(source, position) {
+    static from(source, position): MessageBuffer {
         const buf = new MessageBuffer();
         buf._buffer = Buffer.from(source);
         buf._position = position;
@@ -48,7 +57,7 @@
         this._capacity = this._length;
     }
 
-    get position() {
+    get position(): number {
         return this._position;
     }
 
@@ -56,19 +65,19 @@
         this._position = position;
     }
 
-    get length() {
+    get length(): number {
         return this._length;
     }
 
-    get data() {
+    get data(): Buffer {
         return this.getSlice(0, this.length);
     }
 
-    get buffer() {
+    get buffer(): Buffer {
         return this._buffer;
     }
 
-    getSlice(start, end) {
+    getSlice(start, end): Buffer {
         return this._buffer.slice(start, end);
     }
 
@@ -91,7 +100,7 @@
             }
         }
         catch (err) {
-            throw Errors.IgniteClientError.valueCastError(value, BinaryUtils.TYPE_CODE.LONG);
+            throw IgniteClientError.valueCastError(value, BinaryUtils.TYPE_CODE.LONG);
         }
         const buffer = Buffer.from(value.toBytesLE());
         this.writeBuffer(buffer);
@@ -141,11 +150,11 @@
                     this._buffer.writeDoubleLE(value, this._position);
                     break;
                 default:
-                    throw Errors.IgniteClientError.internalError();
+                    throw IgniteClientError.internalError();
             }
         }
         catch (err) {
-            throw Errors.IgniteClientError.valueCastError(value, type);
+            throw IgniteClientError.valueCastError(value, type);
         }
         this._position += size;
     }
@@ -171,31 +180,31 @@
         this.writeLong(value.getTime());
     }
 
-    readByte() {
+    readByte(): number {
         return this.readNumber(BinaryUtils.TYPE_CODE.BYTE);
     }
 
-    readShort() {
+    readShort(): number {
         return this.readNumber(BinaryUtils.TYPE_CODE.SHORT);
     }
 
-    readInteger() {
+    readInteger(): number {
         return this.readNumber(BinaryUtils.TYPE_CODE.INTEGER);
     }
 
-    readLong() {
+    readLong(): Long {
         const size = BinaryUtils.getSize(BinaryUtils.TYPE_CODE.LONG);
         this._ensureSize(size);
-        const value = Long.fromBytesLE([...this._buffer.slice(this._position, this._position + size)]);
+        const value: Long = Long.fromBytesLE([...this._buffer.slice(this._position, this._position + size)]);
         this._position += size;
         return value;
     }
 
-    readFloat() {
+    readFloat(): number {
         return this.readNumber(BinaryUtils.TYPE_CODE.FLOAT);
     }
 
-    readDouble() {
+    readDouble(): number {
         return this.readNumber(BinaryUtils.TYPE_CODE.DOUBLE);
     }
 
@@ -220,7 +229,7 @@
                 value = this._buffer.readDoubleLE(this._position);
                 break;
             default:
-                throw Errors.IgniteClientError.internalError();
+                throw IgniteClientError.internalError();
         }
         this._position += size;
         return value;
@@ -230,11 +239,11 @@
         return this.readByte() === BYTE_ONE;
     }
 
-    readChar() {
+    readChar(): string {
         return String.fromCharCode(this.readShort());
     }
 
-    readString() {
+    readString(): string {
         const bytesCount = this.readInteger();
         this._ensureSize(bytesCount);
         const result = this._buffer.toString(BinaryUtils.ENCODING, this._position, this._position + bytesCount);
@@ -242,14 +251,14 @@
         return result;
     }
 
-    readBuffer(length) {
+    readBuffer(length): Buffer {
         this._ensureSize(length);
         const result = this._buffer.slice(this._position, this._position + length);
         this._position += length;
         return result;
     }
 
-    readDate() {
+    readDate(): Date {
         return new Date(this.readLong().toNumber());
     }
 
@@ -268,13 +277,13 @@
 
     _ensureSize(size) {
         if (this._position + size > this._length) {
-            throw Errors.IgniteClientError.internalError('Unexpected format of response');
+            throw IgniteClientError.internalError('Unexpected format of response');
         }
     }
 
     _ensureCapacity(valueSize) {
         if (valueSize <= 0) {
-            throw Errors.IgniteClientError.internalError();
+            throw IgniteClientError.internalError();
         }
         let newCapacity = this._capacity;
         while (this._position + valueSize > newCapacity) {
@@ -289,5 +298,3 @@
         }
     }
 }
-
-module.exports = MessageBuffer;
diff --git a/src/internal/PartitionAwarenessUtils.ts b/src/internal/PartitionAwarenessUtils.ts
new file mode 100644
index 0000000..dbbfe7a
--- /dev/null
+++ b/src/internal/PartitionAwarenessUtils.ts
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+'use strict';
+
+import * as Util from 'util';
+import BinaryUtils from "./BinaryUtils";
+import MessageBuffer from "./MessageBuffer";
+import BinaryCommunicator from "./BinaryCommunicator";
+
+export class AffinityTopologyVersion {
+
+    private _major: number;
+
+    private _minor: number;
+
+    constructor(payload) {
+        this._major = payload.readLong();
+        this._minor = payload.readInteger();
+    }
+
+    compareTo(other) {
+        let diff = this._major - other._major;
+        if (diff !== 0) {
+            return diff;
+        }
+        return this._minor - other._minor;
+    }
+
+    equals(other) {
+        return this.compareTo(other) === 0;
+    }
+
+    toString() {
+        return Util.format('%d.%d', this._major, this._minor);
+    }
+}
+
+export class PartitionAwarenessCacheGroup {
+
+    private _caches: Array<[number, Map<number, number>]>;
+
+    private _partitionMap: Array<[number, number[]]>;
+
+    constructor(caches: Array<[number, Map<number, number>]>, partitionMap: Array<[number, number[]]>) {
+        this._caches = caches;
+        this._partitionMap = partitionMap;
+    }
+
+    static async build(communicator, payload) {
+        const applicable = payload.readBoolean();
+
+        const cachesNum = payload.readInteger();
+        const caches = new Array<[number, Map<number, number>]>(cachesNum);
+
+        for (let i = 0; i < cachesNum; i++) {
+            const cacheId = payload.readInteger();
+
+            if (!applicable) {
+                caches[i] = [cacheId, new Map()];
+                continue;
+            }
+
+            caches[i] = [cacheId, this._readCacheKeyConfig(payload)];
+        }
+
+        if (!applicable) {
+            return new PartitionAwarenessCacheGroup(caches, []);
+        }
+
+        const partitionMap: Array<[number, number[]]> = await this._readPartitionMap(communicator, payload);
+
+        return new PartitionAwarenessCacheGroup(caches, partitionMap);
+    }
+
+    get caches(): Array<[number, Map<number, number>]> {
+        // Array [[cacheId, cfg]]
+        return this._caches;
+    }
+
+    get partitionMap(): Array<[number, number[]]> {
+        // Array [[nodeId, [partitions]]]
+        return this._partitionMap;
+    }
+
+    static _readCacheKeyConfig(payload): Map<number, number> {
+        const configsNum = payload.readInteger();
+        // {Key Type ID -> Affinity Key Field ID}
+        let configs = new Map();
+
+        if (configsNum > 0) {
+            for (let i = 0; i < configsNum; i++) {
+                const keyTypeId = payload.readInteger();
+                const affinityKeyFieldId = payload.readInteger();
+
+                configs.set(keyTypeId, affinityKeyFieldId);
+            }
+        }
+
+        return configs;
+    }
+
+    static async _readPartitionMap(communicator: BinaryCommunicator, payload: MessageBuffer): Promise<Array<[number, number[]]>> {
+        const partitionMapSize = payload.readInteger();
+        // [[nodeId, [partitions]]]
+        const partitionMap = new Array<[number, number[]]>(partitionMapSize);
+
+        for (let i = 0; i < partitionMapSize; i++) {
+            const nodeId = await communicator.readObject(payload, BinaryUtils.TYPE_CODE.UUID);
+            const partitionsNum = payload.readInteger();
+            const partitions = new Array<number>(partitionsNum);
+
+            for (let j = 0; j < partitionsNum; j++) {
+                partitions[j] = payload.readInteger();
+            }
+
+            partitionMap[i] = [nodeId, partitions];
+        }
+
+        return partitionMap;
+    }
+}
+
+export class CacheAffinityMap {
+
+    private _cacheId: number;
+
+    // Map {partition -> nodeId}, nodeId is UUID represented by array of bytes
+    private _partitionMapping: Map<number, number[]>;
+
+    // Map {Key Type ID -> Affinity Key Field ID}
+    private _keyConfig: Map<number, number>;
+
+    constructor(cacheId: number, partitionMapping: Map<number, number[]>, keyConfig: Map<number, number>) {
+        this._cacheId = cacheId;
+        this._partitionMapping = partitionMapping;
+        this._keyConfig = keyConfig;
+    }
+
+    get cacheId(): number {
+        return this._cacheId;
+    }
+
+    get partitionMapping(): Map<number, number[]> {
+        return this._partitionMapping;
+    }
+
+    get keyConfig(): Map<number, number> {
+        return this._keyConfig;
+    }
+}
+
+export class RendezvousAffinityFunction {
+    static calcPartition(keyHash, partitionsNum): number {
+        const mask = (partitionsNum & (partitionsNum - 1)) == 0 ? partitionsNum - 1 : -1;
+
+        if (mask >= 0) {
+            return (keyHash ^ (keyHash >> 16)) & mask;
+        }
+
+        return Math.abs(keyHash % partitionsNum);
+    }
+}
diff --git a/src/internal/Router.ts b/src/internal/Router.ts
new file mode 100644
index 0000000..63464a7
--- /dev/null
+++ b/src/internal/Router.ts
@@ -0,0 +1,536 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+'use strict';
+
+import * as Util from "util";
+import { IgniteClient, IgniteClientOnStateChanged, STATE } from "../IgniteClient";
+import ClientSocket from "./ClientSocket";
+import BinaryUtils from "./BinaryUtils";
+import { BinaryObject } from "../BinaryObject";
+import Logger from "./Logger";
+import { AffinityTopologyVersion, CacheAffinityMap, PartitionAwarenessCacheGroup, RendezvousAffinityFunction } from "./PartitionAwarenessUtils";
+import { IgniteClientError, LostConnectionError, IllegalStateError } from "../Errors";
+import BinaryCommunicator from "./BinaryCommunicator";
+import { IgniteClientConfiguration } from "../IgniteClientConfiguration";
+import {AffinityHint} from "../CacheClient";
+import {PRIMITIVE_TYPE} from "./Constants";
+import {CompositeType} from "../ObjectType";
+
+export default class Router {
+
+    private _state: STATE;
+    private _connections: { [key: string]: ClientSocket };
+    private _partitionAwarenessAllowed: boolean;
+    private _partitionAwarenessActive: boolean;
+    private _distributionMap: Map<number, CacheAffinityMap>;
+    private _communicator: BinaryCommunicator;
+    private _config: IgniteClientConfiguration;
+    private _onStateChanged: IgniteClientOnStateChanged;
+    private _inactiveEndpoints: string[];
+    private _backgroundConnectTask: Promise<void>;
+    private _legacyConnection: ClientSocket;
+    private _affinityTopologyVer: AffinityTopologyVersion;
+
+    constructor(onStateChanged: IgniteClientOnStateChanged) {
+        this._state = IgniteClient.STATE.DISCONNECTED;
+        this._onStateChanged = onStateChanged;
+
+        this._partitionAwarenessAllowed = false;
+        // ClientSocket instance with no node UUID
+        this._legacyConnection = null;
+        // Array of endpoints which we are not connected to. Mostly used when Partition Awareness is on
+        this._inactiveEndpoints = [];
+
+        /** Partition Awareness only fields */
+        // This flag indicates if we have at least two alive connections
+        this._partitionAwarenessActive = false;
+        // Contains the background task (promise) or null
+        this._backgroundConnectTask = null;
+        // {Node UUID -> ClientSocket instance}
+        this._connections = {};
+        // {cacheId -> CacheAffinityMap}
+        this._distributionMap = new Map<number, CacheAffinityMap>();
+        this._affinityTopologyVer = null;
+    }
+
+    async connect(communicator: BinaryCommunicator, config: IgniteClientConfiguration) {
+        if (this._state !== STATE.DISCONNECTED) {
+            throw new IllegalStateError(this._state);
+        }
+
+        // Wait for background task to stop before we move forward
+        await this._waitBackgroundConnect();
+
+        this._communicator = communicator;
+        this._config = config;
+        this._partitionAwarenessAllowed = config.partitionAwareness;
+        this._inactiveEndpoints = [...config.endpoints];
+
+        await this._connect();
+    }
+
+    disconnect() {
+        if (this._state !== IgniteClient.STATE.DISCONNECTED) {
+            this._changeState(IgniteClient.STATE.DISCONNECTED);
+
+            for (const socket of this._getAllConnections()) {
+                    socket.disconnect();
+            }
+
+            this._cleanUp();
+        }
+    }
+
+    async send(opCode, payloadWriter, payloadReader = null, affinityHint: AffinityHint = null) {
+        if (this._state !== IgniteClient.STATE.CONNECTED) {
+            throw new IllegalStateError(this._state);
+        }
+
+        if (this._partitionAwarenessActive && affinityHint) {
+            await this._affinitySend(opCode, payloadWriter, payloadReader, affinityHint);
+        }
+        else {
+            // If _partitionAwarenessActive flag is not set, we have exactly one connection
+            // but it can be either a legacy one or a modern one (with node UUID)
+            // If affinityHint has not been passed, we want to always use one socket (as long as it is alive)
+            // because some requests (e.g., SQL cursor-related) require to be sent to the same cluster node
+            await this._getAllConnections()[0].sendRequest(opCode, payloadWriter, payloadReader);
+        }
+    }
+
+    async _connect() {
+        const errors = [];
+        const endpoints = this._inactiveEndpoints;
+        const config = this._config;
+        const communicator = this._communicator;
+        const onSocketDisconnect = this._onSocketDisconnect.bind(this);
+        const onAffinityTopologyChange = this._onAffinityTopologyChange.bind(this);
+        const endpointsNum = endpoints.length;
+        const random = this._getRandomInt(endpointsNum);
+
+        this._changeState(IgniteClient.STATE.CONNECTING);
+
+        for (let i = 0; i < endpoints.length; i++) {
+            const index = (i + random) % endpointsNum;
+            const endpoint = endpoints[index];
+
+            try {
+                const socket = new ClientSocket(
+                    endpoint, config, communicator,
+                    onSocketDisconnect,
+                    onAffinityTopologyChange);
+
+                await socket.connect();
+                Logger.logDebug(Util.format('Connected to %s', endpoint));
+                this._changeState(IgniteClient.STATE.CONNECTED);
+                this._addConnection(socket);
+
+                this._runBackgroundConnect();
+
+                return;
+            }
+            catch (err) {
+                Logger.logDebug(Util.format('Could not connect to %s. Error: "%s"', endpoint, err.message));
+                errors.push(Util.format('[%s] %s', endpoint, err.message));
+            }
+        }
+
+        const error = errors.join('; ');
+        this._changeState(IgniteClient.STATE.DISCONNECTED, error);
+        throw new IgniteClientError(error);
+    }
+
+    // Can be called when there are no alive connections left
+    async _reconnect() {
+        await this._waitBackgroundConnect();
+        await this._connect();
+    }
+
+    _runBackgroundConnect() {
+        if (this._partitionAwarenessAllowed && !this._backgroundConnectTask) {
+            // Only one task can be active
+            this._backgroundConnectTask = this._backgroundConnect();
+            this._backgroundConnectTask.then(() => this._backgroundConnectTask = null);
+        }
+    }
+
+    async _waitBackgroundConnect() {
+        if (this._backgroundConnectTask) {
+            await this._backgroundConnectTask;
+        }
+    }
+
+    async _backgroundConnect(): Promise<void> {
+        // Local copy of _inactiveEndpoints to make sure the array is not being changed during the 'for' cycle
+        const endpoints = [...this._inactiveEndpoints];
+        const config = this._config;
+        const communicator = this._communicator;
+        const onSocketDisconnect = this._onSocketDisconnect.bind(this);
+        const onAffinityTopologyChange = this._onAffinityTopologyChange.bind(this);
+
+        for (const endpoint of endpoints) {
+            const socket = new ClientSocket(
+                endpoint, config, communicator,
+                onSocketDisconnect,
+                onAffinityTopologyChange);
+
+            try {
+                await socket.connect();
+                Logger.logDebug(Util.format('Connected (in background) to %s', endpoint));
+
+                // While we were waiting for socket to connect, someone could call disconnect()
+                if (this._state !== IgniteClient.STATE.CONNECTED) {
+                    // If became not connected, stop this task
+                    socket.disconnect();
+                    return;
+                }
+
+                this._addConnection(socket);
+            }
+            catch (err) {
+                Logger.logDebug(Util.format('Could not connect (in background) to %s. Error: "%s"', endpoint, err.message));
+
+                // While we were waiting for socket to connect, someone could call disconnect()
+                if (this._state !== IgniteClient.STATE.CONNECTED) {
+                    // If became not connected, stop this task
+                    socket.disconnect();
+                    return;
+                }
+            }
+        }
+    }
+
+    _cleanUp() {
+        this._legacyConnection = null;
+        this._inactiveEndpoints = [];
+
+        this._partitionAwarenessActive = false;
+        this._connections = {};
+        this._distributionMap = new Map();
+        this._affinityTopologyVer = null;
+    }
+
+    _getAllConnections() {
+        const allConnections = Object.values(this._connections);
+
+        if (this._legacyConnection) {
+            allConnections.push(this._legacyConnection);
+        }
+
+        return allConnections;
+    }
+
+    _addConnection(socket: ClientSocket) {
+        const nodeUUID = socket.nodeUUID;
+
+        if (this._partitionAwarenessAllowed && nodeUUID) {
+            if (nodeUUID in this._connections) {
+                // This can happen if the same node has several IPs
+                // We will keep more fresh connection alive
+                this._connections[nodeUUID].disconnect();
+            }
+            this._connections[nodeUUID] = socket;
+        }
+        else {
+            if (this._legacyConnection) {
+                // We already have a legacy connection
+                // We will keep more fresh connection alive
+                this._legacyConnection.disconnect();
+            }
+            this._legacyConnection = socket;
+        }
+        // Remove the endpoint from _inactiveEndpoints
+        const index = this._inactiveEndpoints.indexOf(socket.endpoint);
+        if (index > -1) {
+            this._inactiveEndpoints.splice(index, 1);
+        }
+
+        if (!this._partitionAwarenessActive &&
+            this._getAllConnections().length >= 2) {
+            this._partitionAwarenessActive = true;
+        }
+    }
+
+    _removeConnection(socket) {
+        if (socket.nodeUUID in this._connections) {
+            delete this._connections[socket.nodeUUID];
+            // Add the endpoint to _inactiveEndpoints
+            this._inactiveEndpoints.push(socket.endpoint);
+        }
+        else if (this._legacyConnection == socket) {
+            this._legacyConnection = null;
+            // Add the endpoint to _inactiveEndpoints
+            this._inactiveEndpoints.push(socket.endpoint);
+        }
+
+        if (this._partitionAwarenessActive &&
+            this._getAllConnections().length < 2) {
+            this._partitionAwarenessActive = false;
+        }
+    }
+
+    async _onSocketDisconnect(socket, error = null) {
+        this._removeConnection(socket);
+
+        if (this._getAllConnections().length != 0) {
+            // We had more than one connection before this disconnection
+            this._runBackgroundConnect();
+            return;
+        }
+
+        try {
+            await this._reconnect();
+        }
+        catch (err) {
+            this._cleanUp();
+        }
+    }
+
+    /** Partition Awareness methods */
+
+    async _affinitySend(opCode, payloadWriter, payloadReader, affinityHint: AffinityHint) {
+        let connection = await this._chooseConnection(affinityHint);
+
+        while (true) {
+            Logger.logDebug('Endpoint chosen: ' + connection.endpoint);
+
+            try {
+                await connection.sendRequest(opCode, payloadWriter, payloadReader);
+                return;
+            }
+            catch (err) {
+                if (!(err instanceof LostConnectionError)) {
+                    throw err;
+                }
+
+                Logger.logDebug(connection.endpoint + ' is unavailable');
+
+                this._removeConnection(connection);
+
+                if (this._getAllConnections().length == 0) {
+                    throw new LostConnectionError('Cluster is unavailable');
+                }
+            }
+
+            connection = this._getRandomConnection();
+            Logger.logDebug('Node has been chosen randomly');
+        }
+    }
+
+    async _chooseConnection(affinityHint: AffinityHint) {
+        const cacheId = affinityHint.cacheId;
+
+        if (!this._distributionMap.has(cacheId)) {
+            Logger.logDebug('Distribution map does not have info for the cache ' + cacheId);
+            Logger.logDebug('Node has been chosen randomly');
+            // We are not awaiting here in order to not increase latency of requests
+            this._getCachePartitions(cacheId);
+            return this._getRandomConnection();
+        }
+
+        const cacheAffinityMap = this._distributionMap.get(cacheId);
+
+        // node id in cache affinity map is represented by byte array, so we have to convert it to string in order to use
+        // as connections map key
+        const nodeId: string = "" + await this._determineNodeId(cacheAffinityMap,
+                                                   affinityHint.key,
+                                                   affinityHint.keyType);
+
+        if (nodeId in this._connections) {
+            Logger.logDebug('Node has been chosen by affinity');
+            return this._connections[nodeId];
+        }
+
+        Logger.logDebug('Node has been chosen randomly');
+        return this._getRandomConnection();
+    }
+
+    async _determineNodeId(cacheAffinityMap: CacheAffinityMap, key: object, keyType: PRIMITIVE_TYPE | CompositeType): Promise<number[] | null> {
+        const partitionMap: Map<number, number[]> = cacheAffinityMap.partitionMapping;
+
+        if (partitionMap.size == 0) {
+            return null;
+        }
+
+        const keyAffinityMap = cacheAffinityMap.keyConfig;
+
+        const affinityKeyInfo = await this._affinityKeyInfo(key, keyType);
+
+        let affinityKey = affinityKeyInfo.key;
+        let affinityKeyTypeCode = affinityKeyInfo.typeCode;
+
+        if ('typeId' in affinityKeyInfo && keyAffinityMap.has(affinityKeyInfo.typeId)) {
+            const affinityKeyTypeId = keyAffinityMap.get(affinityKeyInfo.typeId);
+
+            if (affinityKey instanceof BinaryObject &&
+                ((<BinaryObject>affinityKey).fields.has(affinityKeyTypeId))) {
+                const field = affinityKey.fields.get(affinityKeyTypeId);
+                affinityKey = await field.getValue();
+                affinityKeyTypeCode = field.typeCode;
+            }
+        }
+
+        const keyHash = await BinaryUtils.hashCode(affinityKey, this._communicator, affinityKeyTypeCode);
+        const partition = RendezvousAffinityFunction.calcPartition(keyHash, partitionMap.size);
+        Logger.logDebug('Partition = ' + partition);
+
+        const nodeId: number[] = partitionMap.get(partition);
+        Logger.logDebug('Node ID = ' + nodeId);
+
+        return nodeId;
+    }
+
+    async _affinityKeyInfo(key, keyType) {
+        let typeCode = BinaryUtils.getTypeCode(keyType ? keyType : BinaryUtils.calcObjectType(key));
+
+        if (typeCode == BinaryUtils.TYPE_CODE.BINARY_OBJECT) {
+            return {'key': key, 'typeCode': typeCode, 'typeId': key._getTypeId()};
+        }
+
+        if (typeCode == BinaryUtils.TYPE_CODE.COMPLEX_OBJECT) {
+            const binObj = await BinaryObject.fromObject(key, keyType);
+            typeCode = BinaryUtils.TYPE_CODE.BINARY_OBJECT;
+
+            return {'key': binObj, 'typeCode': typeCode, 'typeId': binObj._getTypeId()};
+        }
+
+        return {'key': key, 'typeCode': typeCode};
+    }
+
+    async _onAffinityTopologyChange(newVersion) {
+        if (!this._versionIsNewer(newVersion)) {
+            return;
+        }
+
+        Logger.logDebug('New topology version reported: ' + newVersion);
+
+        this._affinityTopologyVer = newVersion;
+        this._distributionMap = new Map();
+
+        this._runBackgroundConnect();
+    }
+
+    async _getCachePartitions(cacheId) {
+        Logger.logDebug('Getting cache partitions info...');
+
+        try {
+            await this.send(
+                BinaryUtils.OPERATION.CACHE_PARTITIONS,
+                async (payload) => {
+                    // We always request partition map for one cache
+                    payload.writeInteger(1);
+                    payload.writeInteger(cacheId);
+                },
+                this._handleCachePartitions.bind(this));
+        }
+        catch (err) {
+            Logger.logDebug('Could not get partitions info: ' + err.message);
+        }
+    }
+
+    async _handleCachePartitions(payload) {
+        const affinityTopologyVer = new AffinityTopologyVersion(payload);
+        Logger.logDebug('Partitions info for topology version ' + affinityTopologyVer);
+
+        if (this._versionIsNewer(affinityTopologyVer)) {
+            this._distributionMap = new Map();
+            this._affinityTopologyVer = affinityTopologyVer;
+            Logger.logDebug('New affinity topology version: ' + affinityTopologyVer);
+        } else if (this._versionIsOlder(affinityTopologyVer)) {
+            Logger.logDebug('Topology version is outdated. Actual version: ' + this._affinityTopologyVer);
+            return;
+        }
+
+        const groupsNum = payload.readInteger();
+        Logger.logDebug('Partitions info for ' + groupsNum + ' cache groups received');
+
+        for (let i = 0; i < groupsNum; i++) {
+            const group = await PartitionAwarenessCacheGroup.build(this._communicator, payload);
+            // {partition -> nodeId}
+            const partitionMapping = new Map();
+
+            for (const [nodeId, partitions] of group.partitionMap) {
+                for (const partition of partitions) {
+                    partitionMapping.set(partition, nodeId);
+                }
+            }
+
+            for (const [cacheId, config] of group.caches) {
+                const cacheAffinityMap = new CacheAffinityMap(cacheId, partitionMapping, config);
+                this._distributionMap.set(cacheId, cacheAffinityMap);
+                Logger.logDebug('Partitions info for cache: ' + cacheId);
+            }
+        }
+
+        Logger.logDebug('Got cache partitions info');
+    }
+
+    _getRandomConnection() {
+        const allConnections = this._getAllConnections();
+        return allConnections[this._getRandomInt(allConnections.length)];
+    }
+
+    _changeState(state, reason = null) {
+        if (Logger.debug) {
+            Logger.logDebug(Util.format('Router state: %s -> %s'),
+                this._getState(this._state),
+                this._getState(state));
+        }
+        if (this._state !== state) {
+            this._state = state;
+            if (this._onStateChanged) {
+                this._onStateChanged(state, reason);
+            }
+        }
+    }
+
+    _getState(state) {
+        switch (state) {
+            case IgniteClient.STATE.DISCONNECTED:
+                return 'DISCONNECTED';
+            case IgniteClient.STATE.CONNECTING:
+                return 'CONNECTING';
+            case IgniteClient.STATE.CONNECTED:
+                return 'CONNECTED';
+            default:
+                return 'UNKNOWN';
+        }
+    }
+
+    _versionIsNewer(version) {
+        return this._affinityTopologyVer === null ||
+               this._affinityTopologyVer.compareTo(version) < 0;
+    }
+
+    _versionIsOlder(version) {
+        return this._affinityTopologyVer !== null &&
+               this._affinityTopologyVer.compareTo(version) > 0;
+    }
+
+    // Returns a random integer between 0 and max - 1
+    _getRandomInt(max) {
+        if (max === 0) {
+            return 0;
+        }
+        return Math.floor(Math.random() * max);
+    }
+
+    _sleep(milliseconds) {
+        return new Promise(resolve => setTimeout(resolve, milliseconds));
+    }
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..e9c6972
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "outDir": "./dist",
+    "lib": ["ES2015"],
+    "target": "es6",
+    "downlevelIteration": true,
+    "sourceMap": true,
+    "module": "CommonJS",
+    "declaration": true,
+    "declarationMap": true
+  },
+  "exclude": [
+    "node_modules"
+  ],
+  "include": ["./src/**/*"]
+}
\ No newline at end of file