diff --git a/immutable/immutable-tests.ts b/immutable/immutable-tests.ts
new file mode 100644
index 0000000000..17240ebe9c
--- /dev/null
+++ b/immutable/immutable-tests.ts
@@ -0,0 +1,329 @@
+///
+
+import immutable = require('immutable')
+
+// List tests
+
+let list: immutable.List = immutable.List([0, 1, 2, 3, 4, 5]);
+let list1: immutable.List = immutable.List(list);
+
+list = immutable.List.of(0, 1, 2, 3, 4);
+let bool: boolean = immutable.List.isList(list);
+
+list = list.set(0, 1);
+list = list.delete(0);
+list = list.remove(0);
+list = list.insert(0, 1);
+list = list.clear();
+list = list.push(0, 1, 2, 3, 4, 5);
+list = list.pop();
+list = list.unshift(1, 2, 3);
+list = list.shift();
+list = list.update((value: immutable.List) => value);
+list = list.update(1, (value: number) => value);
+list = list.update(1, 1, (value: number) => value);
+list = list.merge(list1, list);
+list = list.merge([0, 1, 2], [3, 4, 5]);
+list = list.mergeWith((prev: number, next: number, key: number) => prev, list, list1);
+list = list.mergeWith((prev: number, next: number, key: number) => prev, [0, 1, 2], [3, 4, 5]);
+list = list.mergeDeep(list1, list);
+list = list.mergeDeep([0, 1, 2], [3, 4, 5]);
+list = list.mergeDeepWith((prev: number, next: number, key: number) => prev, list, list1);
+list = list.mergeDeepWith((prev: number, next: number, key: number) => prev, [0, 1, 2], [3, 4, 5]);
+list = list.setSize(5);
+list = list.setIn([0, 1, 2], 5);
+list = list.deleteIn([0, 1, 2]);
+list = list.removeIn([0, 1, 2]);
+list = list.updateIn([0, 1, 2], value => value);
+list = list.updateIn([0, 1, 2], 1, value => value);
+list = list.mergeIn([0, 1, 2], list, list1);
+list = list.mergeIn([0, 1, 2], [0, 1, 2], [3, 4, 5]);
+list = list.mergeDeepIn([0, 1, 2], list, list1);
+list = list.mergeDeepIn([0, 1, 2], [0, 1, 2], [3, 4, 5]);
+list = list.withMutations((mutable: immutable.List) => mutable);
+list = list.asMutable();
+list = list.asImmutable();
+
+// Collection.Indexed
+let indexedSeq: immutable.Seq.Indexed = list.toSeq();
+
+// Iterable tests
+let value: number = list.get(0);
+value = list.get(0, 1);
+list = list.interpose(0);
+list = list.interleave(list, list1);
+list = list.splice(0, 2, 4, 5, 6);
+list = list.zip(list1);
+let indexedIterable: immutable.Iterable.Indexed = list.zipWith(
+ (value: number, other: number) => value + other,
+ list1
+);
+let indexedIterable1: immutable.Iterable.Indexed = list.zipWith(
+ (value: number, other: number, third: number) => value + other + third,
+ list1,
+ indexedIterable
+);
+indexedIterable = list.zipWith(
+ (value: number, other: number, third: number) => value + other + third,
+ list1,
+ indexedIterable1
+);
+value = list.indexOf(1);
+value = list.lastIndexOf(1);
+value = list.findIndex((value: number, index: number, iter: immutable.List) => true);
+value = list.findLastIndex((value: number, index: number, iter: immutable.List) => true);
+value = list.size;
+
+bool = list.equals(list1);
+value = list.hashCode();
+bool = list.has(1);
+bool = list.includes(1);
+bool = list.contains(1);
+value = list.first();
+value = list.last();
+let toArr: number[] = list.toArray();
+let toMap: immutable.Map = list.toMap();
+let toOrderedMap: immutable.OrderedMap = list.toOrderedMap();
+let toSet: immutable.Set = list.toSet();
+let toOrderedSet: immutable.OrderedSet = list.toOrderedSet();
+list = list.toList();
+let toStack: immutable.Stack = list.toStack();
+let toKeyedSeq: immutable.Seq.Keyed = list.toKeyedSeq();
+indexedSeq = list.toIndexedSeq();
+let toSetSeq: immutable.Seq.Set = list.toSetSeq();
+
+let iter: immutable.Iterator = list.keys();
+iter = list.values();
+let iter1: immutable.Iterator<[number, number]> = list.entries();
+
+indexedSeq = list.keySeq();
+indexedSeq = list.valueSeq();
+let indexedSeq1: immutable.Seq.Indexed<[number, number]> = list.entrySeq();
+
+let iter2: immutable.Iterable = list.map(
+ (value: number, key: number, iter: immutable.List) => "foo"
+)
+
+list = list.filterNot((value: number, key: number, iter: immutable.List) => true);
+list = list.reverse();
+list = list.sort((valA: number, valB: number) => 0);
+list = list.sortBy(
+ (value: number, key: number, iter: immutable.List) => "foo",
+ (valueA: string, valueB: string) => 0
+);
+
+let keyedSeq2: immutable.Seq.Keyed> = list.groupBy(
+ (value: number, key: number, iter: immutable.List) => ""
+);
+
+value = list.forEach((value: number, key: number, iter: immutable.List) => true);
+list = list.slice(0, 1);
+list = list.rest();
+list = list.butLast();
+list = list.skip(0);
+list = list.skipLast(0);
+list = list.skipWhile(
+ (value: number, key: number, iter: immutable.List) => true
+);
+list = list.take(2);
+list = list.takeLast(2);
+list = list.takeWhile(
+ (value: number, key: number, iter: immutable.List) => true
+);
+list = list.takeUntil(
+ (value: number, key: number, iter: immutable.List) => true
+);
+list = list.concat(list1, 2, 3);
+list = list.flatten(1);
+list = list.flatten(true);
+let str: string = list.reduce(
+ (red: string, value: number, key: number, iter: immutable.List) => red + "bar",
+ "foo"
+);
+str = list.reduceRight(
+ (red: string, value: number, key: number, iter: immutable.List) => red + "bar",
+ "foo"
+);
+bool = list.every(
+ (value: number, key: number, iter: immutable.List) => true
+);
+bool = list.some(
+ (value: number, key: number, iter: immutable.List) => true
+);
+str = list.join(",");
+bool = list.isEmpty();
+value = list.count();
+value = list.count(
+ (value: number, key: number, iter: immutable.List) => true
+);
+let keyedSeq3: immutable.Seq.Keyed = list.countBy(
+ (value: number, key: number, iter: immutable.List) => "foo"
+);
+value = list.find(
+ (value: number, key: number, iter: immutable.List) => true,
+ null,
+ 0
+);
+value = list.findLast(
+ (value: number, key: number, iter: immutable.List) => true,
+ null,
+ 0
+);
+let tuple: [number, number] = list.findEntry(
+ (value: number, key: number, iter: immutable.List) => true,
+ null,
+ 0
+);
+tuple = list.findLastEntry(
+ (value: number, key: number, iter: immutable.List) => true,
+ null,
+ 0
+);
+value = list.findKey(
+ (value: number, key: number, iter: immutable.List) => true,
+ null
+);
+value = list.findLastKey(
+ (value: number, key: number, iter: immutable.List) => true,
+ null
+);
+value = list.keyOf(0);
+value = list.lastKeyOf(0);
+value = list.max((valA: number, valB: number) => 0);
+value = list.maxBy(
+ (value: number, key: number, iter: immutable.List) => "foo",
+ (valueA: string, valueB: string) => 0
+);
+value = list.min((valA: number, valB: number) => 0);
+value = list.minBy(
+ (value: number, key: number, iter: immutable.List) => "foo",
+ (valueA: string, valueB: string) => 0
+);
+bool = list.isSubset(list1);
+bool = list.isSubset([0, 1, 2]);
+bool = list.isSuperset(list1);
+bool = list.isSuperset([0, 1, 2]);
+
+
+// Map tests
+
+let map: immutable.Map = immutable.Map();
+map = immutable.Map([["foo", 1], ["bar", 2]]);
+let map1: immutable.Map = immutable.Map(map);
+map = map.set("baz", 3);
+map.delete("foo");
+map.remove("foo");
+map = map.clear();
+map = map.update((value: immutable.Map) => value);
+map = map.update("foo", (value: number) => value);
+map = map.update("bar", 1, (value: number) => value);
+map = map.merge(map1, map);
+map = map.merge({ "foo": 0, "bar": 1}, {"baz": 2});
+map = map.mergeWith((prev: number, next: number, key: string) => prev, map, map1);
+map = map.mergeWith((prev: number, next: number, key: string) => prev,{ "foo": 0, "bar": 1}, {"baz": 2});
+map = map.mergeDeep(map1, map);
+map = map.mergeDeep({ "foo": 0, "bar": 1}, {"baz": 2});
+map = map.mergeDeepWith((prev: number, next: number, key: string) => prev, map, map1);
+map = map.mergeDeepWith((prev: number, next: number, key: string) => prev, { "foo": 0, "bar": 1}, {"baz": 2});
+map = map.setIn([0, 1, 2], 5);
+map = map.deleteIn([0, 1, 2]);
+map = map.removeIn([0, 1, 2]);
+map = map.updateIn([0, 1, 2], value => value);
+map = map.updateIn([0, 1, 2], 1, value => value);
+map = map.mergeIn([0, 1, 2], map, map1);
+map = map.mergeIn([0, 1, 2], { "foo": 0, "bar": 1}, {"baz": 2});
+map = map.mergeDeepIn([0, 1, 2], map, map1);
+map = map.mergeDeepIn([0, 1, 2], { "foo": 0, "bar": 1}, {"baz": 2});
+map = map.withMutations((mutable: immutable.Map) => mutable);
+map = map.asMutable();
+map = map.asImmutable();
+
+bool = immutable.Map.isMap(map);
+map = immutable.Map.of("foo", 0, "bar", 1);
+
+// OrderedMap tests
+bool = immutable.OrderedMap.isOrderedMap(toOrderedMap);
+toOrderedMap = immutable.OrderedMap(toOrderedMap);
+
+// Set tests
+let set: immutable.Set = immutable.Set.of(0, 1, 2, 3);
+bool = immutable.Set.isSet(set);
+set = immutable.Set.fromKeys(toMap);
+let set1: immutable.Set = immutable.Set.fromKeys({ "foo": 1, "bar": 2});
+set = immutable.Set();
+set = immutable.Set(set);
+set = set.add(3);
+set.delete(1);
+set.remove(2);
+set = set.clear();
+set = set.union(map, list);
+set = set.union([1, 2, 3], [4, 5, 6]);
+set = set.merge(map1, list);
+set = set.merge([1, 2, 3], [4, 5, 6]);
+set = set.intersect(map1, list);
+set = set.intersect([1, 2, 3], [4, 5, 6]);
+set = set.subtract(map1, list);
+set = set.subtract([1, 2, 3], [4, 5, 6]);
+set = set.withMutations((mutable: immutable.Set) => mutable);
+set = set.asMutable();
+set = set.asImmutable();
+
+
+// OrderedSet tests
+bool = immutable.OrderedSet.isOrderedSet(set);
+let orderedSet1: immutable.OrderedSet = immutable.OrderedSet.of(0, 1, 2, 3);
+orderedSet1 = immutable.OrderedSet.fromKeys(toMap);
+let orderedSet2: immutable.Set = immutable.Set.fromKeys({ "foo": 1, "bar": 2});
+
+// Stack tests
+
+let stack: immutable.Stack = immutable.Stack();
+bool = immutable.Stack.isStack(stack);
+stack = immutable.Stack.of(0, 1, 2, 3, 4, 5);
+stack = immutable.Stack(list);
+value = stack.peek();
+stack = stack.clear();
+stack = stack.unshift(0, 1, 2);
+stack = stack.unshiftAll(list);
+stack = stack.unshiftAll([1, 2, 3]);
+stack = stack.shift();
+stack = stack.push(1, 2, 3);
+stack = stack.pushAll(list);
+stack = stack.pushAll([1, 2, 3]);
+stack = stack.pop();
+stack = stack.withMutations((mutable: immutable.Stack) => mutable);
+stack = stack.asMutable();
+stack = stack.asImmutable();
+
+
+// Range and Repeat function tests
+
+let funcSeqIndexed: immutable.Seq.Indexed = immutable.Range(0, 3, 1);
+funcSeqIndexed = immutable.Repeat(2, 10);
+
+
+// Seq tests
+let seq: immutable.Seq = immutable.Seq();
+bool = immutable.Seq.isSeq(seq);
+funcSeqIndexed = immutable.Seq.of(0, 1, 2, 3);
+seq = immutable.Seq(map);
+value = seq.size;
+seq = seq.cacheResult();
+
+
+// keyed
+let seqKeyed: immutable.Seq.Keyed = immutable.Seq.Keyed();
+seqKeyed = immutable.Seq.Keyed(map);
+seqKeyed = seqKeyed.toSeq();
+
+// indexed
+let seqIndexed: immutable.Seq.Indexed = immutable.Seq.Indexed();
+seqIndexed = immutable.Seq.Indexed.of(0, 1, 2, 3);
+seqIndexed = immutable.Seq.Indexed(list);
+seqIndexed = seqIndexed.toSeq();
+
+// indexed
+let seqSet: immutable.Seq.Set = immutable.Seq.Set();
+seqSet = immutable.Seq.Set.of(0, 1, 2, 3);
+seqSet = immutable.Seq.Set(list);
+seqSet = seqSet.toSeq();
diff --git a/immutable/immutable.d.ts b/immutable/immutable.d.ts
new file mode 100644
index 0000000000..5ca32ecfe4
--- /dev/null
+++ b/immutable/immutable.d.ts
@@ -0,0 +1,2546 @@
+// Type definitions for Facebook's Immutable 3.8.1
+// Project: https://github.com/facebook/immutable-js
+// Definitions by: tht13
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+// Core of typings are from repository itself
+
+/**
+ * Copyright (c) 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+/**
+ * Immutable data encourages pure functions (data-in, data-out) and lends itself
+ * to much simpler application development and enabling techniques from
+ * functional programming such as lazy evaluation.
+ *
+ * While designed to bring these powerful functional concepts to JavaScript, it
+ * presents an Object-Oriented API familiar to Javascript engineers and closely
+ * mirroring that of Array, Map, and Set. It is easy and efficient to convert to
+ * and from plain Javascript types.
+
+ * Note: all examples are presented in [ES6][]. To run in all browsers, they
+ * need to be translated to ES3. For example:
+ *
+ * // ES6
+ * foo.map(x => x * x);
+ * // ES3
+ * foo.map(function (x) { return x * x; });
+ *
+ * [ES6]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla
+ */
+
+declare namespace __Immutable {
+
+ /**
+ * Deeply converts plain JS objects and arrays to Immutable Maps and Lists.
+ *
+ * If a `reviver` is optionally provided, it will be called with every
+ * collection as a Seq (beginning with the most nested collections
+ * and proceeding to the top-level collection itself), along with the key
+ * refering to each collection and the parent JS object provided as `this`.
+ * For the top level, object, the key will be `""`. This `reviver` is expected
+ * to return a new Immutable Iterable, allowing for custom conversions from
+ * deep JS objects.
+ *
+ * This example converts JSON to List and OrderedMap:
+ *
+ * Immutable.fromJS({a: {b: [10, 20, 30]}, c: 40}, function (key, value) {
+ * var isIndexed = Immutable.Iterable.isIndexed(value);
+ * return isIndexed ? value.toList() : value.toOrderedMap();
+ * });
+ *
+ * // true, "b", {b: [10, 20, 30]}
+ * // false, "a", {a: {b: [10, 20, 30]}, c: 40}
+ * // false, "", {"": {a: {b: [10, 20, 30]}, c: 40}}
+ *
+ * If `reviver` is not provided, the default behavior will convert Arrays into
+ * Lists and Objects into Maps.
+ *
+ * `reviver` acts similarly to the [same parameter in `JSON.parse`][1].
+ *
+ * `Immutable.fromJS` is conservative in its conversion. It will only convert
+ * arrays which pass `Array.isArray` to Lists, and only raw objects (no custom
+ * prototype) to Map.
+ *
+ * Keep in mind, when using JS objects to construct Immutable Maps, that
+ * JavaScript Object properties are always strings, even if written in a
+ * quote-less shorthand, while Immutable Maps accept keys of any type.
+ *
+ * ```js
+ * var obj = { 1: "one" };
+ * Object.keys(obj); // [ "1" ]
+ * obj["1"]; // "one"
+ * obj[1]; // "one"
+ *
+ * var map = Map(obj);
+ * map.get("1"); // "one"
+ * map.get(1); // undefined
+ * ```
+ *
+ * Property access for JavaScript Objects first converts the key to a string,
+ * but since Immutable Map keys can be of any type the argument to `get()` is
+ * not altered.
+ *
+ * [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter
+ * "Using the reviver parameter"
+ */
+ export function fromJS(
+ json: any,
+ reviver?: (k: any, v: Iterable) => any
+ ): any;
+
+
+ /**
+ * Value equality check with semantics similar to `Object.is`, but treats
+ * Immutable `Iterable`s as values, equal if the second `Iterable` includes
+ * equivalent values.
+ *
+ * It's used throughout Immutable when checking for equality, including `Map`
+ * key equality and `Set` membership.
+ *
+ * var map1 = Immutable.Map({a:1, b:1, c:1});
+ * var map2 = Immutable.Map({a:1, b:1, c:1});
+ * assert(map1 !== map2);
+ * assert(Object.is(map1, map2) === false);
+ * assert(Immutable.is(map1, map2) === true);
+ *
+ * Note: Unlike `Object.is`, `Immutable.is` assumes `0` and `-0` are the same
+ * value, matching the behavior of ES6 Map key equality.
+ */
+ export function is(first: any, second: any): boolean;
+
+
+ /**
+ * Lists are ordered indexed dense collections, much like a JavaScript
+ * Array.
+ *
+ * Lists are immutable and fully persistent with O(log32 N) gets and sets,
+ * and O(1) push and pop.
+ *
+ * Lists implement Deque, with efficient addition and removal from both the
+ * end (`push`, `pop`) and beginning (`unshift`, `shift`).
+ *
+ * Unlike a JavaScript Array, there is no distinction between an
+ * "unset" index and an index set to `undefined`. `List#forEach` visits all
+ * indices from 0 to size, regardless of whether they were explicitly defined.
+ */
+ export module List {
+
+ /**
+ * True if the provided value is a List
+ */
+ function isList(maybeList: any): boolean;
+
+ /**
+ * Creates a new List containing `values`.
+ */
+ function of(...values: T[]): List;
+ }
+
+ /**
+ * Create a new immutable List containing the values of the provided
+ * iterable-like.
+ */
+ export function List(): List;
+ export function List(iter: Iterable.Indexed): List;
+ export function List(iter: Iterable.Set): List;
+ export function List(iter: Iterable.Keyed): List<[K,V]>;
+ export function List(array: Array): List;
+ export function List(iterator: Iterator): List;
+ export function List(iterable: Iterable): List;
+
+
+ export interface List extends Collection.Indexed {
+
+ // Persistent changes
+
+ /**
+ * Returns a new List which includes `value` at `index`. If `index` already
+ * exists in this List, it will be replaced.
+ *
+ * `index` may be a negative number, which indexes back from the end of the
+ * List. `v.set(-1, "value")` sets the last item in the List.
+ *
+ * If `index` larger than `size`, the returned List's `size` will be large
+ * enough to include the `index`.
+ */
+ set(index: number, value: T): List;
+
+ /**
+ * Returns a new List which excludes this `index` and with a size 1 less
+ * than this List. Values at indices above `index` are shifted down by 1 to
+ * fill the position.
+ *
+ * This is synonymous with `list.splice(index, 1)`.
+ *
+ * `index` may be a negative number, which indexes back from the end of the
+ * List. `v.delete(-1)` deletes the last item in the List.
+ *
+ * Note: `delete` cannot be safely used in IE8
+ * @alias remove
+ */
+ delete(index: number): List;
+ remove(index: number): List;
+
+ /**
+ * Returns a new List with `value` at `index` with a size 1 more than this
+ * List. Values at indices above `index` are shifted over by 1.
+ *
+ * This is synonymous with `list.splice(index, 0, value)
+ */
+ insert(index: number, value: T): List;
+
+ /**
+ * Returns a new List with 0 size and no values.
+ */
+ clear(): List;
+
+ /**
+ * Returns a new List with the provided `values` appended, starting at this
+ * List's `size`.
+ */
+ push(...values: T[]): List;
+
+ /**
+ * Returns a new List with a size ones less than this List, excluding
+ * the last index in this List.
+ *
+ * Note: this differs from `Array#pop` because it returns a new
+ * List rather than the removed value. Use `last()` to get the last value
+ * in this List.
+ */
+ pop(): List;
+
+ /**
+ * Returns a new List with the provided `values` prepended, shifting other
+ * values ahead to higher indices.
+ */
+ unshift(...values: T[]): List;
+
+ /**
+ * Returns a new List with a size ones less than this List, excluding
+ * the first index in this List, shifting all other values to a lower index.
+ *
+ * Note: this differs from `Array#shift` because it returns a new
+ * List rather than the removed value. Use `first()` to get the first
+ * value in this List.
+ */
+ shift(): List;
+
+ /**
+ * Returns a new List with an updated value at `index` with the return
+ * value of calling `updater` with the existing value, or `notSetValue` if
+ * `index` was not set. If called with a single argument, `updater` is
+ * called with the List itself.
+ *
+ * `index` may be a negative number, which indexes back from the end of the
+ * List. `v.update(-1)` updates the last item in the List.
+ *
+ * @see `Map#update`
+ */
+ update(updater: (value: List) => List): List;
+ update(index: number, updater: (value: T) => T): List;
+ update(index: number, notSetValue: T, updater: (value: T) => T): List;
+
+ /**
+ * @see `Map#merge`
+ */
+ merge(...iterables: Iterable.Indexed[]): List;
+ merge(...iterables: Array[]): List;
+
+ /**
+ * @see `Map#mergeWith`
+ */
+ mergeWith(
+ merger: (previous?: T, next?: T, key?: number) => T,
+ ...iterables: Iterable.Indexed[]
+ ): List;
+ mergeWith(
+ merger: (previous?: T, next?: T, key?: number) => T,
+ ...iterables: Array[]
+ ): List;
+
+ /**
+ * @see `Map#mergeDeep`
+ */
+ mergeDeep(...iterables: Iterable.Indexed[]): List;
+ mergeDeep(...iterables: Array[]): List;
+
+ /**
+ * @see `Map#mergeDeepWith`
+ */
+ mergeDeepWith(
+ merger: (previous?: T, next?: T, key?: number) => T,
+ ...iterables: Iterable.Indexed[]
+ ): List;
+ mergeDeepWith(
+ merger: (previous?: T, next?: T, key?: number) => T,
+ ...iterables: Array[]
+ ): List;
+
+ /**
+ * Returns a new List with size `size`. If `size` is less than this
+ * List's size, the new List will exclude values at the higher indices.
+ * If `size` is greater than this List's size, the new List will have
+ * undefined values for the newly available indices.
+ *
+ * When building a new List and the final size is known up front, `setSize`
+ * used in conjunction with `withMutations` may result in the more
+ * performant construction.
+ */
+ setSize(size: number): List;
+
+
+ // Deep persistent changes
+
+ /**
+ * Returns a new List having set `value` at this `keyPath`. If any keys in
+ * `keyPath` do not exist, a new immutable Map will be created at that key.
+ *
+ * Index numbers are used as keys to determine the path to follow in
+ * the List.
+ */
+ setIn(keyPath: Array, value: any): List;
+ setIn(keyPath: Iterable, value: any): List;
+
+ /**
+ * Returns a new List having removed the value at this `keyPath`. If any
+ * keys in `keyPath` do not exist, no change will occur.
+ *
+ * @alias removeIn
+ */
+ deleteIn(keyPath: Array): List;
+ deleteIn(keyPath: Iterable): List;
+ removeIn(keyPath: Array): List;
+ removeIn(keyPath: Iterable): List;
+
+ /**
+ * @see `Map#updateIn`
+ */
+ updateIn(
+ keyPath: Array,
+ updater: (value: any) => any
+ ): List;
+ updateIn(
+ keyPath: Array,
+ notSetValue: any,
+ updater: (value: any) => any
+ ): List;
+ updateIn(
+ keyPath: Iterable,
+ updater: (value: any) => any
+ ): List;
+ updateIn(
+ keyPath: Iterable,
+ notSetValue: any,
+ updater: (value: any) => any
+ ): List;
+
+ /**
+ * @see `Map#mergeIn`
+ */
+ mergeIn(
+ keyPath: Iterable,
+ ...iterables: Iterable.Indexed[]
+ ): List;
+ mergeIn(
+ keyPath: Array,
+ ...iterables: Iterable.Indexed[]
+ ): List;
+ mergeIn(
+ keyPath: Array,
+ ...iterables: Array[]
+ ): List;
+
+ /**
+ * @see `Map#mergeDeepIn`
+ */
+ mergeDeepIn(
+ keyPath: Iterable,
+ ...iterables: Iterable.Indexed[]
+ ): List;
+ mergeDeepIn(
+ keyPath: Array,
+ ...iterables: Iterable.Indexed[]
+ ): List;
+ mergeDeepIn(
+ keyPath: Array,
+ ...iterables: Array[]
+ ): List;
+
+
+ // Transient changes
+
+ /**
+ * Note: Not all methods can be used on a mutable collection or within
+ * `withMutations`! Only `set`, `push`, `pop`, `shift`, `unshift` and
+ * `merge` may be used mutatively.
+ *
+ * @see `Map#withMutations`
+ */
+ withMutations(mutator: (mutable: List) => any): List;
+
+ /**
+ * @see `Map#asMutable`
+ */
+ asMutable(): List;
+
+ /**
+ * @see `Map#asImmutable`
+ */
+ asImmutable(): List;
+ }
+
+
+ /**
+ * Immutable Map is an unordered Iterable.Keyed of (key, value) pairs with
+ * `O(log32 N)` gets and `O(log32 N)` persistent sets.
+ *
+ * Iteration order of a Map is undefined, however is stable. Multiple
+ * iterations of the same Map will iterate in the same order.
+ *
+ * Map's keys can be of any type, and use `Immutable.is` to determine key
+ * equality. This allows the use of any value (including NaN) as a key.
+ *
+ * Because `Immutable.is` returns equality based on value semantics, and
+ * Immutable collections are treated as values, any Immutable collection may
+ * be used as a key.
+ *
+ * Map().set(List.of(1), 'listofone').get(List.of(1));
+ * // 'listofone'
+ *
+ * Any JavaScript object may be used as a key, however strict identity is used
+ * to evaluate key equality. Two similar looking objects will represent two
+ * different keys.
+ *
+ * Implemented by a hash-array mapped trie.
+ */
+ export module Map {
+
+ /**
+ * True if the provided value is a Map
+ */
+ function isMap(maybeMap: any): boolean;
+
+ /**
+ * Creates a new Map from alternating keys and values
+ */
+ function of(...keyValues: (K|V)[]): Map;
+ }
+
+ /**
+ * Creates a new Immutable Map.
+ *
+ * Created with the same key value pairs as the provided Iterable.Keyed or
+ * JavaScript Object or expects an Iterable of [K, V] tuple entries.
+ *
+ * var newMap = Map({key: "value"});
+ * var newMap = Map([["key", "value"]]);
+ *
+ * Keep in mind, when using JS objects to construct Immutable Maps, that
+ * JavaScript Object properties are always strings, even if written in a
+ * quote-less shorthand, while Immutable Maps accept keys of any type.
+ *
+ * ```js
+ * var obj = { 1: "one" };
+ * Object.keys(obj); // [ "1" ]
+ * obj["1"]; // "one"
+ * obj[1]; // "one"
+ *
+ * var map = Map(obj);
+ * map.get("1"); // "one"
+ * map.get(1); // undefined
+ * ```
+ *
+ * Property access for JavaScript Objects first converts the key to a string,
+ * but since Immutable Map keys can be of any type the argument to `get()` is
+ * not altered.
+ */
+ export function Map(): Map;
+ export function Map(iter: Iterable.Keyed): Map;
+ export function Map(iter: Iterable): Map;
+ export function Map(array: Array<[K,V]>): Map;
+ export function Map(obj: {[key: string]: V}): Map;
+ export function Map(iterator: Iterator<[K,V]>): Map;
+ export function Map(iterable: Iterable): Map;
+
+ export interface Map extends Collection.Keyed {
+
+ // Persistent changes
+
+ /**
+ * Returns a new Map also containing the new key, value pair. If an equivalent
+ * key already exists in this Map, it will be replaced.
+ */
+ set(key: K, value: V): Map;
+
+ /**
+ * Returns a new Map which excludes this `key`.
+ *
+ * Note: `delete` cannot be safely used in IE8, but is provided to mirror
+ * the ES6 collection API.
+ * @alias remove
+ */
+ delete(key: K): Map;
+ remove(key: K): Map;
+
+ /**
+ * Returns a new Map containing no keys or values.
+ */
+ clear(): Map;
+
+ /**
+ * Returns a new Map having updated the value at this `key` with the return
+ * value of calling `updater` with the existing value, or `notSetValue` if
+ * the key was not set. If called with only a single argument, `updater` is
+ * called with the Map itself.
+ *
+ * Equivalent to: `map.set(key, updater(map.get(key, notSetValue)))`.
+ */
+ update(updater: (value: Map) => Map): Map;
+ update(key: K, updater: (value: V) => V): Map;
+ update(key: K, notSetValue: V, updater: (value: V) => V): Map;
+
+ /**
+ * Returns a new Map resulting from merging the provided Iterables
+ * (or JS objects) into this Map. In other words, this takes each entry of
+ * each iterable and sets it on this Map.
+ *
+ * If any of the values provided to `merge` are not Iterable (would return
+ * false for `Immutable.Iterable.isIterable`) then they are deeply converted
+ * via `Immutable.fromJS` before being merged. However, if the value is an
+ * Iterable but includes non-iterable JS objects or arrays, those nested
+ * values will be preserved.
+ *
+ * var x = Immutable.Map({a: 10, b: 20, c: 30});
+ * var y = Immutable.Map({b: 40, a: 50, d: 60});
+ * x.merge(y) // { a: 50, b: 40, c: 30, d: 60 }
+ * y.merge(x) // { b: 20, a: 10, d: 60, c: 30 }
+ *
+ */
+ merge(...iterables: Iterable[]): Map;
+ merge(...iterables: {[key: string]: V}[]): Map;
+
+ /**
+ * Like `merge()`, `mergeWith()` returns a new Map resulting from merging
+ * the provided Iterables (or JS objects) into this Map, but uses the
+ * `merger` function for dealing with conflicts.
+ *
+ * var x = Immutable.Map({a: 10, b: 20, c: 30});
+ * var y = Immutable.Map({b: 40, a: 50, d: 60});
+ * x.mergeWith((prev, next) => prev / next, y) // { a: 0.2, b: 0.5, c: 30, d: 60 }
+ * y.mergeWith((prev, next) => prev / next, x) // { b: 2, a: 5, d: 60, c: 30 }
+ *
+ */
+ mergeWith(
+ merger: (previous?: V, next?: V, key?: K) => V,
+ ...iterables: Iterable[]
+ ): Map;
+ mergeWith(
+ merger: (previous?: V, next?: V, key?: K) => V,
+ ...iterables: {[key: string]: V}[]
+ ): Map;
+
+ /**
+ * Like `merge()`, but when two Iterables conflict, it merges them as well,
+ * recursing deeply through the nested data.
+ *
+ * var x = Immutable.fromJS({a: { x: 10, y: 10 }, b: { x: 20, y: 50 } });
+ * var y = Immutable.fromJS({a: { x: 2 }, b: { y: 5 }, c: { z: 3 } });
+ * x.mergeDeep(y) // {a: { x: 2, y: 10 }, b: { x: 20, y: 5 }, c: { z: 3 } }
+ *
+ */
+ mergeDeep(...iterables: Iterable[]): Map;
+ mergeDeep(...iterables: {[key: string]: V}[]): Map;
+
+ /**
+ * Like `mergeDeep()`, but when two non-Iterables conflict, it uses the
+ * `merger` function to determine the resulting value.
+ *
+ * var x = Immutable.fromJS({a: { x: 10, y: 10 }, b: { x: 20, y: 50 } });
+ * var y = Immutable.fromJS({a: { x: 2 }, b: { y: 5 }, c: { z: 3 } });
+ * x.mergeDeepWith((prev, next) => prev / next, y)
+ * // {a: { x: 5, y: 10 }, b: { x: 20, y: 10 }, c: { z: 3 } }
+ *
+ */
+ mergeDeepWith(
+ merger: (previous?: V, next?: V, key?: K) => V,
+ ...iterables: Iterable[]
+ ): Map;
+ mergeDeepWith(
+ merger: (previous?: V, next?: V, key?: K) => V,
+ ...iterables: {[key: string]: V}[]
+ ): Map;
+
+
+ // Deep persistent changes
+
+ /**
+ * Returns a new Map having set `value` at this `keyPath`. If any keys in
+ * `keyPath` do not exist, a new immutable Map will be created at that key.
+ */
+ setIn(keyPath: Array, value: any): Map;
+ setIn(KeyPath: Iterable, value: any): Map;
+
+ /**
+ * Returns a new Map having removed the value at this `keyPath`. If any keys
+ * in `keyPath` do not exist, no change will occur.
+ *
+ * @alias removeIn
+ */
+ deleteIn(keyPath: Array): Map;
+ deleteIn(keyPath: Iterable): Map;
+ removeIn(keyPath: Array): Map;
+ removeIn(keyPath: Iterable): Map;
+
+ /**
+ * Returns a new Map having applied the `updater` to the entry found at the
+ * keyPath.
+ *
+ * If any keys in `keyPath` do not exist, new Immutable `Map`s will
+ * be created at those keys. If the `keyPath` does not already contain a
+ * value, the `updater` function will be called with `notSetValue`, if
+ * provided, otherwise `undefined`.
+ *
+ * var data = Immutable.fromJS({ a: { b: { c: 10 } } });
+ * data = data.updateIn(['a', 'b', 'c'], val => val * 2);
+ * // { a: { b: { c: 20 } } }
+ *
+ * If the `updater` function returns the same value it was called with, then
+ * no change will occur. This is still true if `notSetValue` is provided.
+ *
+ * var data1 = Immutable.fromJS({ a: { b: { c: 10 } } });
+ * data2 = data1.updateIn(['x', 'y', 'z'], 100, val => val);
+ * assert(data2 === data1);
+ *
+ */
+ updateIn(
+ keyPath: Array,
+ updater: (value: any) => any
+ ): Map;
+ updateIn(
+ keyPath: Array,
+ notSetValue: any,
+ updater: (value: any) => any
+ ): Map;
+ updateIn(
+ keyPath: Iterable,
+ updater: (value: any) => any
+ ): Map