diff --git a/js-combinatorics/js-combinatorics-global-tests.ts b/js-combinatorics/js-combinatorics-global-tests.ts
new file mode 100644
index 0000000000..b8cbd3525c
--- /dev/null
+++ b/js-combinatorics/js-combinatorics-global-tests.ts
@@ -0,0 +1,93 @@
+///
+
+const p:number = Combinatorics.P(1, 2);
+const c:number = Combinatorics.C(1, 2);
+const factorial:number = Combinatorics.factorial(5);
+const factoradic:number[] = Combinatorics.factoradic(5);
+
+const power = Combinatorics.power(["a", "b", "c"]);
+const nextPower:string[] = power.next();
+power.forEach((i:string[]) => console.log(i));
+const powersLengths:number[] = power.map((i:string[]) => i.length);
+const filteredPowers:string[][] = power.filter((i:string[]) => i.length > 0);
+const allPowers:string[][] = power.toArray();
+const powersCount = power.length;
+const nthPower:string[] = power.nth(3);
+
+const limitedCombination = Combinatorics.combination(["a", "b", "c"], 2);
+const combination = Combinatorics.combination(["a", "b", "c"]);
+const nextCombination:string[] = combination.next();
+combination.forEach((i:string[]) => console.log(i));
+const combinationsLengths:number[] = combination.map((i:string[]) => i.length);
+const filteredCombinations:string[][] = combination.filter((i:string[]) => i.length > 0);
+const allCombinations:string[][] = combination.toArray();
+const combinationsCount = combination.length;
+
+const limitedPermutation = Combinatorics.permutation(["a", "b", "c"], 2);
+const permutation = Combinatorics.permutation(["a", "b", "c"]);
+const nextPermutation:string[] = permutation.next();
+permutation.forEach((i:string[]) => console.log(i));
+const permutationsLengths:number[] = permutation.map((i:string[]) => i.length);
+const filteredPermutations:string[][] = permutation.filter((i:string[]) => i.length > 0);
+const allPermutations:string[][] = permutation.toArray();
+const permutationsCount = permutation.length;
+
+const permutationCombination = Combinatorics.permutationCombination(["a", "b", "c"]);
+const nextPermutationCombinations:string[] = permutationCombination.next();
+permutationCombination.forEach((i:string[]) => console.log(i));
+const permutationCombinationsLengths:number[] = permutationCombination.map((i:string[]) => i.length);
+const filteredPermutationCombinationss:string[][] = permutationCombination.filter((i:string[]) => i.length > 0);
+const allPermutationCombinationss:string[][] = permutationCombination.toArray();
+const permutationCombinationsCount = permutationCombination.length;
+
+const limitedBaseN = Combinatorics.baseN(["a", "b", "c"], 2);
+const baseN = Combinatorics.baseN(["a", "b", "c"]);
+const nextbaseN:string[] = baseN.next();
+baseN.forEach((i:string[]) => console.log(i));
+const baseNsLengths:number[] = baseN.map((i:string[]) => i.length);
+const filteredbaseNs:string[][] = baseN.filter((i:string[]) => i.length > 0);
+const allbaseNs:string[][] = baseN.toArray();
+const baseNsCount = baseN.length;
+const nthbaseN:string[] = baseN.nth(3);
+
+const cartesianProduct1 = Combinatorics.cartesianProduct(["a", "b", "c"]);
+const nextCartesianProduct1:[string] = cartesianProduct1.next();
+cartesianProduct1.forEach((i:[string]) => console.log(i));
+const cartesianProduct1sLengths:number[] = cartesianProduct1.map((i:[string]) => i.length);
+const filteredCartesianProduct1s:[string][] = cartesianProduct1.filter((i:[string]) => i.length > 0);
+const allCartesianProduct1s:[string][] = cartesianProduct1.toArray();
+const cartesianProduct1sCount = cartesianProduct1.length;
+const nthCartesianProduct1:[string] = cartesianProduct1.nth(3);
+const cartesianProduct1ByCoords:[string] = cartesianProduct1.get(1);
+
+const cartesianProduct2 = Combinatorics.cartesianProduct(["a", "b", "c"], [1, 2, 3]);
+const nextCartesianProduct2:[string, number] = cartesianProduct2.next();
+cartesianProduct2.forEach((i:[string, number]) => console.log(i));
+const cartesianProduct2sLengths:number[] = cartesianProduct2.map((i:[string, number]) => i.length);
+const filteredCartesianProduct2s:[string, number][] = cartesianProduct2.filter((i:[string, number]) => i.length > 0);
+const allCartesianProduct2s:[string, number][] = cartesianProduct2.toArray();
+const cartesianProduct2sCount = cartesianProduct2.length;
+const nthCartesianProduct2:[string, number] = cartesianProduct2.nth(3);
+const cartesianProduct2ByCoords:[string, number] = cartesianProduct2.get(1, 1);
+
+const cartesianProduct3 = Combinatorics.cartesianProduct(["a", "b", "c"], [1, 2, 3], [true, false]);
+const nextCartesianProduct3:[string, number, boolean] = cartesianProduct3.next();
+cartesianProduct3.forEach((i:[string, number, boolean]) => console.log(i));
+const cartesianProduct3sLengths:number[] = cartesianProduct3.map((i:[string, number, boolean]) => i.length);
+const filteredCartesianProduct3s:[string, number, boolean][] = cartesianProduct3.filter((i:[string, number, boolean]) => i.length > 0);
+const allCartesianProduct3s:[string, number, boolean][] = cartesianProduct3.toArray();
+const cartesianProduct3sCount = cartesianProduct3.length;
+const nthCartesianProduct3:[string, number, boolean] = cartesianProduct3.nth(3);
+const cartesianProduct3ByCoords:[string, number, boolean] = cartesianProduct3.get(1, 1);
+
+const cartesianProductAny = Combinatorics.cartesianProduct(["a", 1, true], [false, 2, "b"]);
+const nextCartesianProductAny:any[] = cartesianProductAny.next();
+cartesianProductAny.forEach((i:any[]) => console.log(i));
+const cartesianProductAnysLengths:number[] = cartesianProductAny.map((i:any[]) => i.length);
+const filteredCartesianProductAnys:any[][] = cartesianProductAny.filter((i:any[]) => i.length > 0);
+const allCartesianProductAnys:any[][] = cartesianProductAny.toArray();
+const cartesianProductAnysCount = cartesianProductAny.length;
+const nthCartesianProductAny:any[] = cartesianProductAny.nth(3);
+const cartesianProductAnyByCoords:any[] = cartesianProductAny.get(1, 1);
+
+const version:string = Combinatorics.VERSION;
\ No newline at end of file
diff --git a/js-combinatorics/js-combinatorics-global.d.ts b/js-combinatorics/js-combinatorics-global.d.ts
new file mode 100644
index 0000000000..20c302981c
--- /dev/null
+++ b/js-combinatorics/js-combinatorics-global.d.ts
@@ -0,0 +1,8 @@
+// Type definitions for js-combinatorics v0.5.0 (global)
+// Project: https://github.com/dankogai/js-combinatorics
+// Definitions by: Vasya Aksyonov
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+
+import Combinatorics = __Combinatorics;
diff --git a/js-combinatorics/js-combinatorics-tests.ts b/js-combinatorics/js-combinatorics-tests.ts
new file mode 100644
index 0000000000..08e04c374f
--- /dev/null
+++ b/js-combinatorics/js-combinatorics-tests.ts
@@ -0,0 +1,95 @@
+///
+
+import * as Combinatorics from "js-combinatorics";
+
+const p:number = Combinatorics.P(1, 2);
+const c:number = Combinatorics.C(1, 2);
+const factorial:number = Combinatorics.factorial(5);
+const factoradic:number[] = Combinatorics.factoradic(5);
+
+const power = Combinatorics.power(["a", "b", "c"]);
+const nextPower:string[] = power.next();
+power.forEach((i:string[]) => console.log(i));
+const powersLengths:number[] = power.map((i:string[]) => i.length);
+const filteredPowers:string[][] = power.filter((i:string[]) => i.length > 0);
+const allPowers:string[][] = power.toArray();
+const powersCount = power.length;
+const nthPower:string[] = power.nth(3);
+
+const limitedCombination = Combinatorics.combination(["a", "b", "c"], 2);
+const combination = Combinatorics.combination(["a", "b", "c"]);
+const nextCombination:string[] = combination.next();
+combination.forEach((i:string[]) => console.log(i));
+const combinationsLengths:number[] = combination.map((i:string[]) => i.length);
+const filteredCombinations:string[][] = combination.filter((i:string[]) => i.length > 0);
+const allCombinations:string[][] = combination.toArray();
+const combinationsCount = combination.length;
+
+const limitedPermutation = Combinatorics.permutation(["a", "b", "c"], 2);
+const permutation = Combinatorics.permutation(["a", "b", "c"]);
+const nextPermutation:string[] = permutation.next();
+permutation.forEach((i:string[]) => console.log(i));
+const permutationsLengths:number[] = permutation.map((i:string[]) => i.length);
+const filteredPermutations:string[][] = permutation.filter((i:string[]) => i.length > 0);
+const allPermutations:string[][] = permutation.toArray();
+const permutationsCount = permutation.length;
+
+const permutationCombination = Combinatorics.permutationCombination(["a", "b", "c"]);
+const nextPermutationCombinations:string[] = permutationCombination.next();
+permutationCombination.forEach((i:string[]) => console.log(i));
+const permutationCombinationsLengths:number[] = permutationCombination.map((i:string[]) => i.length);
+const filteredPermutationCombinationss:string[][] = permutationCombination.filter((i:string[]) => i.length > 0);
+const allPermutationCombinationss:string[][] = permutationCombination.toArray();
+const permutationCombinationsCount = permutationCombination.length;
+
+const limitedBaseN = Combinatorics.baseN(["a", "b", "c"], 2);
+const baseN = Combinatorics.baseN(["a", "b", "c"]);
+const nextbaseN:string[] = baseN.next();
+baseN.forEach((i:string[]) => console.log(i));
+const baseNsLengths:number[] = baseN.map((i:string[]) => i.length);
+const filteredbaseNs:string[][] = baseN.filter((i:string[]) => i.length > 0);
+const allbaseNs:string[][] = baseN.toArray();
+const baseNsCount = baseN.length;
+const nthbaseN:string[] = baseN.nth(3);
+
+const cartesianProduct1 = Combinatorics.cartesianProduct(["a", "b", "c"]);
+const nextCartesianProduct1:[string] = cartesianProduct1.next();
+cartesianProduct1.forEach((i:[string]) => console.log(i));
+const cartesianProduct1sLengths:number[] = cartesianProduct1.map((i:[string]) => i.length);
+const filteredCartesianProduct1s:[string][] = cartesianProduct1.filter((i:[string]) => i.length > 0);
+const allCartesianProduct1s:[string][] = cartesianProduct1.toArray();
+const cartesianProduct1sCount = cartesianProduct1.length;
+const nthCartesianProduct1:[string] = cartesianProduct1.nth(3);
+const cartesianProduct1ByCoords:[string] = cartesianProduct1.get(1);
+
+const cartesianProduct2 = Combinatorics.cartesianProduct(["a", "b", "c"], [1, 2, 3]);
+const nextCartesianProduct2:[string, number] = cartesianProduct2.next();
+cartesianProduct2.forEach((i:[string, number]) => console.log(i));
+const cartesianProduct2sLengths:number[] = cartesianProduct2.map((i:[string, number]) => i.length);
+const filteredCartesianProduct2s:[string, number][] = cartesianProduct2.filter((i:[string, number]) => i.length > 0);
+const allCartesianProduct2s:[string, number][] = cartesianProduct2.toArray();
+const cartesianProduct2sCount = cartesianProduct2.length;
+const nthCartesianProduct2:[string, number] = cartesianProduct2.nth(3);
+const cartesianProduct2ByCoords:[string, number] = cartesianProduct2.get(1, 1);
+
+const cartesianProduct3 = Combinatorics.cartesianProduct(["a", "b", "c"], [1, 2, 3], [true, false]);
+const nextCartesianProduct3:[string, number, boolean] = cartesianProduct3.next();
+cartesianProduct3.forEach((i:[string, number, boolean]) => console.log(i));
+const cartesianProduct3sLengths:number[] = cartesianProduct3.map((i:[string, number, boolean]) => i.length);
+const filteredCartesianProduct3s:[string, number, boolean][] = cartesianProduct3.filter((i:[string, number, boolean]) => i.length > 0);
+const allCartesianProduct3s:[string, number, boolean][] = cartesianProduct3.toArray();
+const cartesianProduct3sCount = cartesianProduct3.length;
+const nthCartesianProduct3:[string, number, boolean] = cartesianProduct3.nth(3);
+const cartesianProduct3ByCoords:[string, number, boolean] = cartesianProduct3.get(1, 1);
+
+const cartesianProductAny = Combinatorics.cartesianProduct(["a", 1, true], [false, 2, "b"]);
+const nextCartesianProductAny:any[] = cartesianProductAny.next();
+cartesianProductAny.forEach((i:any[]) => console.log(i));
+const cartesianProductAnysLengths:number[] = cartesianProductAny.map((i:any[]) => i.length);
+const filteredCartesianProductAnys:any[][] = cartesianProductAny.filter((i:any[]) => i.length > 0);
+const allCartesianProductAnys:any[][] = cartesianProductAny.toArray();
+const cartesianProductAnysCount = cartesianProductAny.length;
+const nthCartesianProductAny:any[] = cartesianProductAny.nth(3);
+const cartesianProductAnyByCoords:any[] = cartesianProductAny.get(1, 1);
+
+const version:string = Combinatorics.VERSION;
diff --git a/js-combinatorics/js-combinatorics.d.ts b/js-combinatorics/js-combinatorics.d.ts
new file mode 100644
index 0000000000..270e98b641
--- /dev/null
+++ b/js-combinatorics/js-combinatorics.d.ts
@@ -0,0 +1,135 @@
+// Type definitions for js-combinatorics v0.5.0
+// Project: https://github.com/dankogai/js-combinatorics
+// Definitions by: Vasya Aksyonov
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+declare namespace __Combinatorics {
+
+ interface IGenerator {
+
+ /**
+ * Returns the element or undefined if no more element is available.
+ */
+ next():T;
+
+ /**
+ * Applies the callback function for each element.
+ */
+ forEach(f:(item:T) => void):void;
+
+ /**
+ * All elements at once with function applied to each element.
+ */
+ map(f:(item:T) => TResult):TResult[];
+
+ /**
+ * Returns an array with elements that passes the filter function.
+ */
+ filter(predicate:(item:T) => boolean):T[];
+
+ /**
+ * All elements at once.
+ */
+ toArray():T[];
+
+ /**
+ * Returns the number of elements to be generated which equals to generator.toArray().length
+ * but it is precalculated without actually generating elements.
+ * Handy when you prepare for large iteration.
+ */
+ length:number;
+
+ }
+
+ interface IPredictableGenerator extends IGenerator {
+
+ /**
+ * Returns the nth element (starting 0).
+ */
+ nth(n:number):T;
+
+ }
+
+ interface ICartesianProductGenerator extends IPredictableGenerator {
+
+ /**
+ * Arguments are coordinates in integer.
+ * Arguments can be out of bounds but it returns undefined in such cases.
+ */
+ get(...coordinates:number[]):T;
+
+ }
+
+ /**
+ * Calculates m P n
+ */
+ function P(m:number, n:number):number;
+
+ /**
+ * Calculates m C n
+ */
+ function C(m:number, n:number):number;
+
+ /**
+ * Calculates n!
+ */
+ function factorial(n:number):number;
+
+ /**
+ * Returns the factoradic representation of n in array, in least significant order.
+ * See http://en.wikipedia.org/wiki/Factorial_number_system
+ */
+ function factoradic(n:number):number[];
+
+ /**
+ * Generates the power set of array.
+ */
+ function power(a:T[]):IPredictableGenerator;
+
+ /**
+ * Generates the combination of array with n elements.
+ * When n is ommited, the length of the array is used.
+ */
+ function combination(a:T[], n?:number):IGenerator;
+
+ /**
+ * Generates the permutation of array with n elements.
+ * When n is ommited, the length of the array is used.
+ */
+ function permutation(a:T[], n?:number):IGenerator;
+
+ /**
+ * Generates the permutation of the combination of n.
+ * Equivalent to permutation(combination(a)), but more efficient.
+ */
+ function permutationCombination(a:T[]):IGenerator;
+
+ /**
+ * Generates n-digit "numbers" where each digit is an element in array.
+ * Note this "number" is in the least significant order.
+ * When n is ommited, the length of the array is used.
+ */
+ function baseN(a:T[], n?:number):IPredictableGenerator;
+
+ /**
+ * Generates the cartesian product of the arrays. All arguments must be arrays with more than one element.
+ */
+ function cartesianProduct(a1:T1[]):ICartesianProductGenerator<[T1]>;
+ function cartesianProduct(a1:T1[], a2:T2[]):ICartesianProductGenerator<[T1, T2]>;
+ function cartesianProduct(a1:T1[], a2:T2[], a3:T3[]):ICartesianProductGenerator<[T1, T2, T3]>;
+ function cartesianProduct(a1:T1[], a2:T2[], a3:T3[], a4:T4[]):ICartesianProductGenerator<[T1, T2, T3, T4]>;
+ function cartesianProduct(a1:T1[], a2:T2[], a3:T3[], a4:T4[], a5:T5[]):ICartesianProductGenerator<[T1, T2, T3, T4, T5]>;
+ function cartesianProduct(a1:T1[], a2:T2[], a3:T3[], a4:T4[], a5:T5[], a6:T6[]):ICartesianProductGenerator<[T1, T2, T3, T4, T5, T6]>;
+ function cartesianProduct(a1:T1[], a2:T2[], a3:T3[], a4:T4[], a5:T5[], a6:T6[], a7:T7[]):ICartesianProductGenerator<[T1, T2, T3, T4, T5, T6, T7]>;
+ function cartesianProduct(a1:T1[], a2:T2[], a3:T3[], a4:T4[], a5:T5[], a6:T6[], a7:T7[], a8:T8[]):ICartesianProductGenerator<[T1, T2, T3, T4, T5, T6, T7, T8]>;
+ function cartesianProduct(a1:T1[], a2:T2[], a3:T3[], a4:T4[], a5:T5[], a6:T6[], a7:T7[], a8:T8[], a9:T9[]):ICartesianProductGenerator<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
+ function cartesianProduct(a1:T1[], a2:T2[], a3:T3[], a4:T4[], a5:T5[], a6:T6[], a7:T7[], a8:T8[], a9:T9[], a10:T10[]):ICartesianProductGenerator<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
+ function cartesianProduct(...a:any[][]):ICartesianProductGenerator;
+
+ const VERSION:string;
+
+}
+
+declare module "js-combinatorics" {
+ export = __Combinatorics;
+}