Skip to content

Instantly share code, notes, and snippets.

@johnfn
Created March 16, 2017 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnfn/12defda0d0548a4b165201f77618f36c to your computer and use it in GitHub Desktop.
Save johnfn/12defda0d0548a4b165201f77618f36c to your computer and use it in GitHub Desktop.
import { Record, Iterator, Iterable, Seq, Map, OrderedMap, OrderedSet, Set, Stack, List } from 'immutable';
import * as Immutable from 'immutable';
export type TypedRecord<T> = Readonly<T> & InnerRecord<T>;
interface InnerRecord<T> {
get<K extends keyof T>(key: K): T[K];
/**
* 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: keyof T, value: T[keyof T]): TypedRecord<T>;
/**
* 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: keyof T): TypedRecord<T>;
remove(key: keyof T): TypedRecord<T>;
/**
* Returns a new Map containing no keys or values.
*/
clear(): TypedRecord<T>;
/**
* 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: TypedRecord<T>) => TypedRecord<T>): TypedRecord<T>;
// dunno why this doesn't work:
// update(key: keyof T, updater: (value: T[keyof T]) => T[keyof T]): TypedRecord<T>;
update<K extends keyof T>(key: K, updater: (value: T[K]) => T[K]): TypedRecord<T>;
update<K extends keyof T>(key: K, notSetValue: T[K], updater: (value: T[K]) => T[K]): Map<K, T[K]>;
/**
* 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<keyof T, T[keyof T]>[]): TypedRecord<T>;
merge(...iterables: Partial<T>[]): TypedRecord<T>;
/**
* 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?: T[keyof T], next?: T[keyof T], key?: keyof T) => T[keyof T],
...iterables: Iterable<keyof T, T[keyof T]>[]
): Map<keyof T, T[keyof T]>;
mergeWith(
merger: (previous?: T[keyof T], next?: T[keyof T], key?: keyof T) => T[keyof T],
...iterables: {[key: string]: T[keyof T]}[]
): Map<string, T[keyof T]>;
/**
* 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<keyof T, T[keyof T]>[]): Map<keyof T, T[keyof T]>;
mergeDeep(...iterables: {[key: string]: T[keyof T]}[]): Map<string, T[keyof T]>;
/**
* 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?: T[keyof T], next?: T[keyof T], key?: keyof T) => T[keyof T],
...iterables: Iterable<keyof T, T[keyof T]>[]
): Map<keyof T, T[keyof T]>;
mergeDeepWith(
merger: (previous?: T[keyof T], next?: T[keyof T], key?: keyof T) => T[keyof T],
...iterables: {[key: string]: T[keyof T]}[]
): Map<string, T[keyof T]>;
// 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<any>, value: any): Map<keyof T, T[keyof T]>;
// setIn(KeyPath: Iterable<any, any>, value: any): Map<keyof T, T[keyof T]>;
setIn<K1 extends keyof T>(keyPath: [K1], value: T[K1]): TypedRecord<T>;
setIn<
K1 extends keyof T,
K2 extends keyof T[K1]
>(keyPath: [K1, K2], value: T[K1][K2]): TypedRecord<T>;
setIn<
K1 extends keyof T,
K2 extends keyof T[K1],
K3 extends keyof T[K1][K2]
>(keyPath: [K1, K2, K3], value: T[K1][K2][K3]): TypedRecord<T>;
/**
* 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<any>): Map<keyof T, T[keyof T]>;
deleteIn(keyPath: Iterable<any, any>): Map<keyof T, T[keyof T]>;
removeIn(keyPath: Array<any>): Map<keyof T, T[keyof T]>;
removeIn(keyPath: Iterable<any, any>): Map<keyof T, T[keyof T]>;
/**
* 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<K1 extends keyof T, K2 extends keyof T[K1]>(
keyPath: [K1, K2],
updater: (value: T[K1][K2]) => T[K1][K2]
): TypedRecord<T>;
updateIn<K1 extends keyof T>(
keyPath: [K1],
updater: (value: T[K1]) => T[K1]
): TypedRecord<T>;
/**
* A combination of `updateIn` and `merge`, returning a new Map, but
* performing the merge at a point arrived at by following the keyPath.
* In other words, these two lines are equivalent:
*
* x.updateIn(['a', 'b', 'c'], abc => abc.merge(y));
* x.mergeIn(['a', 'b', 'c'], y);
*
*/
mergeIn(
keyPath: Iterable<any, any>,
...iterables: Iterable<keyof T, T[keyof T]>[]
): Map<keyof T, T[keyof T]>;
mergeIn(
keyPath: Array<any>,
...iterables: Iterable<keyof T, T[keyof T]>[]
): Map<keyof T, T[keyof T]>;
mergeIn(
keyPath: Array<any>,
...iterables: {[key: string]: T[keyof T]}[]
): Map<string, T[keyof T]>;
/**
* A combination of `updateIn` and `mergeDeep`, returning a new Map, but
* performing the deep merge at a point arrived at by following the keyPath.
* In other words, these two lines are equivalent:
*
* x.updateIn(['a', 'b', 'c'], abc => abc.mergeDeep(y));
* x.mergeDeepIn(['a', 'b', 'c'], y);
*
*/
mergeDeepIn(
keyPath: Iterable<any, any>,
...iterables: Iterable<keyof T, T[keyof T]>[]
): Map<keyof T, T[keyof T]>;
mergeDeepIn(
keyPath: Array<any>,
...iterables: Iterable<keyof T, T[keyof T]>[]
): Map<keyof T, T[keyof T]>;
mergeDeepIn(
keyPath: Array<any>,
...iterables: {[key: string]: T[keyof T]}[]
): Map<string, T[keyof T]>;
// Transient changes
/**
* Every time you call one of the above functions, a new immutable Map is
* created. If a pure function calls a number of these to produce a final
* return value, then a penalty on performance and memory has been paid by
* creating all of the intermediate immutable Maps.
*
* If you need to apply a series of mutations to produce a new immutable
* Map, `withMutations()` creates a temporary mutable copy of the Map which
* can apply mutations in a highly performant manner. In fact, this is
* exactly how complex mutations like `merge` are done.
*
* As an example, this results in the creation of 2, not 4, new Maps:
*
* var map1 = Immutable.Map();
* var map2 = map1.withMutations(map => {
* map.set('a', 1).set('b', 2).set('c', 3);
* });
* assert(map1.size === 0);
* assert(map2.size === 3);
*
* Note: Not all methods can be used on a mutable collection or within
* `withMutations`! Only `set` and `merge` may be used mutatively.
*
*/
withMutations(mutator: (mutable: Map<keyof T, T[keyof T]>) => void): Map<keyof T, T[keyof T]>;
/**
* Another way to avoid creation of intermediate Immutable maps is to create
* a mutable copy of this collection. Mutable copies *always* return `this`,
* and thus shouldn't be used for equality. Your function should never return
* a mutable copy of a collection, only use it internally to create a new
* collection. If possible, use `withMutations` as it provides an easier to
* use API.
*
* Note: if the collection is already mutable, `asMutable` returns itself.
*
* Note: Not all methods can be used on a mutable collection or within
* `withMutations`! Only `set` and `merge` may be used mutatively.
*/
asMutable(): Map<keyof T, T[keyof T]>;
/**
* The yin to `asMutable`'s yang. Because it applies to mutable collections,
* this operation is *mutable* and returns itself. Once performed, the mutable
* copy has become immutable and can be safely returned from a function.
*/
asImmutable(): Map<keyof T, T[keyof T]>;
// Iterable
/**
* True if this and the other Iterable have value equality, as defined
* by `Immutable.is()`.
*
* Note: This is equivalent to `Immutable.is(this, other)`, but provided to
* allow for chained expressions.
*/
equals(other: TypedRecord<T>): boolean;
/**
* Computes and returns the hashed identity for this Iterable.
*
* The `hashCode` of an Iterable is used to determine potential equality,
* and is used when adding this to a `Set` or as a key in a `Map`, enabling
* lookup via a different instance.
*
* var a = List.of(1, 2, 3);
* var b = List.of(1, 2, 3);
* assert(a !== b); // different instances
* var set = Set.of(a);
* assert(set.has(b) === true);
*
* If two values have the same `hashCode`, they are [not guaranteed
* to be equal][Hash Collision]. If two values have different `hashCode`s,
* they must not be equal.
*
* [Hash Collision]: http://en.wikipedia.org/wiki/Collision_(computer_science)
*/
hashCode(): number;
/**
* True if a key exists within this `Iterable`, using `Immutable.is` to determine equality
*/
has(key: keyof T): boolean;
/**
* True if a value exists within this `Iterable`, using `Immutable.is` to determine equality
* @alias contains
*/
includes<K extends keyof T>(value: T[K]): boolean;
contains<K extends keyof T>(value: T[K]): boolean;
/**
* The first value in the Iterable.
*/
first(): T[keyof T];
/**
* The last value in the Iterable.
*/
last(): T[keyof T];
// Reading deep values
getIn(searchKeyPath: Array<any>, notSetValue?: any): any;
getIn(searchKeyPath: Iterable<any, any>, notSetValue?: any): any;
/**
* True if the result of following a path of keys or indices through nested
* Iterables results in a set value.
*/
hasIn(searchKeyPath: Array<any>): boolean;
hasIn(searchKeyPath: Iterable<any, any>): boolean;
// Conversion to JavaScript types
/**
* Deeply converts this Iterable to equivalent JS.
*
* `Iterable.Indexeds`, and `Iterable.Sets` become Arrays, while
* `Iterable.Keyeds` become Objects.
*
* @alias toJSON
*/
toJS(): T;
/**
* Shallowly converts this iterable to an Array, discarding keys.
*/
toArray(): Array<keyof T>;
/**
* Shallowly converts this Iterable to an Object.
*
* Throws if keys are not strings.
*/
toObject(): T;
// Conversion to Collections
/**
* Converts this Iterable to a Map, Throws if keys are not hashable.
*
* Note: This is equivalent to `Map(this.toKeyedSeq())`, but provided
* for convenience and to allow for chained expressions.
*/
toMap(): Map<keyof T, T[keyof T]>;
/**
* Converts this Iterable to a Map, maintaining the order of iteration.
*
* Note: This is equivalent to `OrderedMap(this.toKeyedSeq())`, but
* provided for convenience and to allow for chained expressions.
*/
toOrderedMap(): OrderedMap<keyof T, T[keyof T]>;
/**
* Converts this Iterable to a Set, discarding keys. Throws if values
* are not hashable.
*
* Note: This is equivalent to `Set(this)`, but provided to allow for
* chained expressions.
*/
toSet(): Set<T[keyof T]>;
/**
* Converts this Iterable to a Set, maintaining the order of iteration and
* discarding keys.
*
* Note: This is equivalent to `OrderedSet(this.valueSeq())`, but provided
* for convenience and to allow for chained expressions.
*/
toOrderedSet(): OrderedSet<T[keyof T]>;
/**
* Converts this Iterable to a List, discarding keys.
*
* Note: This is equivalent to `List(this)`, but provided to allow
* for chained expressions.
*/
toList(): List<T[keyof T]>;
/**
* Converts this Iterable to a Stack, discarding keys. Throws if values
* are not hashable.
*
* Note: This is equivalent to `Stack(this)`, but provided to allow for
* chained expressions.
*/
toStack(): Stack<T[keyof T]>;
// Conversion to Seq
/**
* Converts this Iterable to a Seq of the same kind (indexed,
* keyed, or set).
*/
toSeq(): Seq<keyof T, T[keyof T]>;
/**
* Returns a Seq.Keyed from this Iterable where indices are treated as keys.
*
* This is useful if you want to operate on an
* Iterable.Indexed and preserve the [index, value] pairs.
*
* The returned Seq will have identical iteration order as
* this Iterable.
*
* Example:
*
* var indexedSeq = Immutable.Seq.of('A', 'B', 'C');
* indexedSeq.filter(v => v === 'B').toString() // Seq [ 'B' ]
* var keyedSeq = indexedSeq.toKeyedSeq();
* keyedSeq.filter(v => v === 'B').toString() // Seq { 1: 'B' }
*
*/
toKeyedSeq(): Seq.Keyed<keyof T, T[keyof T]>;
/**
* Returns an Seq.Indexed of the values of this Iterable, discarding keys.
*/
toIndexedSeq(): Seq.Indexed<T[keyof T]>;
/**
* Returns a Seq.Set of the values of this Iterable, discarding keys.
*/
toSetSeq(): Seq.Set<T[keyof T]>;
// Iterators
/**
* An iterator of this `Iterable`'s keys.
*
* Note: this will return an ES6 iterator which does not support Immutable JS sequence algorithms. Use `keySeq` instead, if this is what you want.
*/
keys(): Iterator<keyof T>;
/**
* An iterator of this `Iterable`'s values.
*
* Note: this will return an ES6 iterator which does not support Immutable JS sequence algorithms. Use `valueSeq` instead, if this is what you want.
*/
values(): Iterator<T[keyof T]>;
/**
* An iterator of this `Iterable`'s entries as `[key, value]` tuples.
*
* Note: this will return an ES6 iterator which does not support Immutable JS sequence algorithms. Use `entrySeq` instead, if this is what you want.
*/
entries(): Iterator<[T, T[keyof T]]>;
// Iterables (Seq)
/**
* Returns a new Seq.Indexed of the keys of this Iterable,
* discarding values.
*/
keySeq(): Seq.Indexed<keyof T>;
/**
* Returns an Seq.Indexed of the values of this Iterable, discarding keys.
*/
valueSeq(): Seq.Indexed<T[keyof T]>;
/**
* Returns a new Seq.Indexed of [key, value] tuples.
*/
entrySeq(): Seq.Indexed</*(K, V)*/Array<any>>;
// Sequence algorithms
/**
* Returns a new Iterable of the same type with values passed through a
* `mapper` function.
*
* Seq({ a: 1, b: 2 }).map(x => 10 * x)
* // Seq { a: 10, b: 20 }
*
*/
map<M>(
mapper: (value?: keyof T, key?: T[keyof T], iter?: /*this*/Iterable<keyof T, T[keyof T]>) => M,
context?: any
): /*this*/Iterable<keyof T, M>;
/**
* Returns a new Iterable of the same type with only the entries for which
* the `predicate` function returns true.
*
* Seq({a:1,b:2,c:3,d:4}).filter(x => x % 2 === 0)
* // Seq { b: 2, d: 4 }
*
*/
filter(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any
): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type with only the entries for which
* the `predicate` function returns false.
*
* Seq({a:1,b:2,c:3,d:4}).filterNot(x => x % 2 === 0)
* // Seq { a: 1, c: 3 }
*
*/
filterNot(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any
): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type in reverse order.
*/
reverse(): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type which includes the same entries,
* stably sorted by using a `comparator`.
*
* If a `comparator` is not provided, a default comparator uses `<` and `>`.
*
* `comparator(valueA, valueB)`:
*
* * Returns `0` if the elements should not be swapped.
* * Returns `-1` (or any negative number) if `valueA` comes before `valueB`
* * Returns `1` (or any positive number) if `valueA` comes after `valueB`
* * Is pure, i.e. it must always return the same value for the same pair
* of values.
*
* When sorting collections which have no defined order, their ordered
* equivalents will be returned. e.g. `map.sort()` returns OrderedMap.
*/
sort(comparator?: (valueA: T[keyof T], valueB: T[keyof T]) => number): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Like `sort`, but also accepts a `comparatorValueMapper` which allows for
* sorting by more sophisticated means:
*
* hitters.sortBy(hitter => hitter.avgHits);
*
*/
sortBy<C>(
comparatorValueMapper: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => C,
comparator?: (valueA: C, valueB: C) => number
): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a `Iterable.Keyed` of `Iterable.Keyeds`, grouped by the return
* value of the `grouper` function.
*
* Note: This is always an eager operation.
*/
groupBy<G>(
grouper: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => G,
context?: any
): /*Map*/Seq.Keyed<G, /*this*/Iterable<keyof T, T[keyof T]>>;
// Side effects
/**
* The `sideEffect` is executed for every entry in the Iterable.
*
* Unlike `Array#forEach`, if any call of `sideEffect` returns
* `false`, the iteration will stop. Returns the number of entries iterated
* (including the last iteration which returned false).
*/
forEach(
sideEffect: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => any,
context?: any
): number;
// Creating subsets
/**
* Returns a new Iterable of the same type representing a portion of this
* Iterable from start up to but not including end.
*
* If begin is negative, it is offset from the end of the Iterable. e.g.
* `slice(-2)` returns a Iterable of the last two entries. If it is not
* provided the new Iterable will begin at the beginning of this Iterable.
*
* If end is negative, it is offset from the end of the Iterable. e.g.
* `slice(0, -1)` returns an Iterable of everything but the last entry. If
* it is not provided, the new Iterable will continue through the end of
* this Iterable.
*
* If the requested slice is equivalent to the current Iterable, then it
* will return itself.
*/
slice(begin?: number, end?: number): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type containing all entries except
* the first.
*/
rest(): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type containing all entries except
* the last.
*/
butLast(): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type which excludes the first `amount`
* entries from this Iterable.
*/
skip(amount: number): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type which excludes the last `amount`
* entries from this Iterable.
*/
skipLast(amount: number): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type which includes entries starting
* from when `predicate` first returns false.
*
* Seq.of('dog','frog','cat','hat','god')
* .skipWhile(x => x.match(/g/))
* // Seq [ 'cat', 'hat', 'god' ]
*
*/
skipWhile(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any
): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type which includes entries starting
* from when `predicate` first returns true.
*
* Seq.of('dog','frog','cat','hat','god')
* .skipUntil(x => x.match(/hat/))
* // Seq [ 'hat', 'god' ]
*
*/
skipUntil(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any
): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type which includes the first `amount`
* entries from this Iterable.
*/
take(amount: number): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type which includes the last `amount`
* entries from this Iterable.
*/
takeLast(amount: number): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type which includes entries from this
* Iterable as long as the `predicate` returns true.
*
* Seq.of('dog','frog','cat','hat','god')
* .takeWhile(x => x.match(/o/))
* // Seq [ 'dog', 'frog' ]
*
*/
takeWhile(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any
): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Returns a new Iterable of the same type which includes entries from this
* Iterable as long as the `predicate` returns false.
*
* Seq.of('dog','frog','cat','hat','god').takeUntil(x => x.match(/at/))
* // ['dog', 'frog']
*
*/
takeUntil(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any
): /*this*/Iterable<keyof T, T[keyof T]>;
// Combination
/**
* Returns a new Iterable of the same type with other values and
* iterable-like concatenated to this one.
*
* For Seqs, all entries will be present in
* the resulting iterable, even if they have the same key.
*/
concat(...valuesOrIterables: Array<Iterable<keyof T, T[keyof T]> | T[keyof T]>): /*this*/Iterable<keyof T, T[keyof T]>;
/**
* Flattens nested Iterables.
*
* Will deeply flatten the Iterable by default, returning an Iterable of the
* same type, but a `depth` can be provided in the form of a number or
* boolean (where true means to shallowly flatten one level). A depth of 0
* (or shallow: false) will deeply flatten.
*
* Flattens only others Iterable, not Arrays or Objects.
*
* Note: `flatten(true)` operates on Iterable<any, Iterable<K, V>> and
* returns Iterable<K, V>
*/
flatten(depth?: number): /*this*/Iterable<any, any>;
flatten(shallow?: boolean): /*this*/Iterable<any, any>;
/**
* Flat-maps the Iterable, returning an Iterable of the same type.
*
* Similar to `iter.map(...).flatten(true)`.
*/
flatMap<MK, MV>(
mapper: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => Iterable<MK, MV>,
context?: any
): /*this*/Iterable<MK, MV>;
flatMap<MK, MV>(
mapper: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => /*iterable-like*/any,
context?: any
): /*this*/Iterable<MK, MV>;
// Reducing a value
/**
* Reduces the Iterable to a value by calling the `reducer` for every entry
* in the Iterable and passing along the reduced value.
*
* If `initialReduction` is not provided, or is null, the first item in the
* Iterable will be used.
*
* @see `Array#reduce`.
*/
reduce<R>(
reducer: (reduction?: R, value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => R,
initialReduction?: R,
context?: any
): R;
/**
* Reduces the Iterable in reverse (from the right side).
*
* Note: Similar to this.reverse().reduce(), and provided for parity
* with `Array#reduceRight`.
*/
reduceRight<R>(
reducer: (reduction?: R, value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => R,
initialReduction?: R,
context?: any
): R;
/**
* True if `predicate` returns true for all entries in the Iterable.
*/
every(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any
): boolean;
/**
* True if `predicate` returns true for any entry in the Iterable.
*/
some(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any
): boolean;
/**
* Joins values together as a string, inserting a separator between each.
* The default separator is `","`.
*/
join(separator?: string): string;
/**
* Returns true if this Iterable includes no values.
*
* For some lazy `Seq`, `isEmpty` might need to iterate to determine
* emptiness. At most one iteration will occur.
*/
isEmpty(): boolean;
/**
* Returns the size of this Iterable.
*
* Regardless of if this Iterable can describe its size lazily (some Seqs
* cannot), this method will always return the correct size. E.g. it
* evaluates a lazy `Seq` if necessary.
*
* If `predicate` is provided, then this returns the count of entries in the
* Iterable for which the `predicate` returns true.
*/
count(): number;
count(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any
): number;
/**
* Returns a `Seq.Keyed` of counts, grouped by the return value of
* the `grouper` function.
*
* Note: This is not a lazy operation.
*/
countBy<G>(
grouper: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => G,
context?: any
): Map<G, number>;
// Search for value
/**
* Returns the first value for which the `predicate` returns true.
*/
find(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any,
notSetValue?: T[keyof T]
): T[keyof T];
/**
* Returns the last value for which the `predicate` returns true.
*
* Note: `predicate` will be called for each entry in reverse.
*/
findLast(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any,
notSetValue?: T[keyof T]
): T[keyof T];
/**
* Returns the first [key, value] entry for which the `predicate` returns true.
*/
findEntry(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any,
notSetValue?: T[keyof T]
): /*[K, V]*/Array<any>;
/**
* Returns the last [key, value] entry for which the `predicate`
* returns true.
*
* Note: `predicate` will be called for each entry in reverse.
*/
findLastEntry(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => boolean,
context?: any,
notSetValue?: T[keyof T]
): Array<[keyof T, T[keyof T]]>;
/**
* Returns the key for which the `predicate` returns true.
*/
findKey(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable.Keyed<keyof T, T[keyof T]>) => boolean,
context?: any
): keyof T;
/**
* Returns the last key for which the `predicate` returns true.
*
* Note: `predicate` will be called for each entry in reverse.
*/
findLastKey(
predicate: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable.Keyed<keyof T, T[keyof T]>) => boolean,
context?: any
): keyof T;
/**
* Returns the key associated with the search value, or undefined.
*/
keyOf(searchValue: T[keyof T]): keyof T;
/**
* Returns the last key associated with the search value, or undefined.
*/
lastKeyOf(searchValue: T[keyof T]): keyof T;
/**
* Returns the maximum value in this collection. If any values are
* comparatively equivalent, the first one found will be returned.
*
* The `comparator` is used in the same way as `Iterable#sort`. If it is not
* provided, the default comparator is `>`.
*
* When two values are considered equivalent, the first encountered will be
* returned. Otherwise, `max` will operate independent of the order of input
* as long as the comparator is commutative. The default comparator `>` is
* commutative *only* when types do not differ.
*
* If `comparator` returns 0 and either value is NaN, undefined, or null,
* that value will be returned.
*/
max(comparator?: (valueA: T[keyof T], valueB: T[keyof T]) => number): T[keyof T];
/**
* Like `max`, but also accepts a `comparatorValueMapper` which allows for
* comparing by more sophisticated means:
*
* hitters.maxBy(hitter => hitter.avgHits);
*
*/
maxBy<C>(
comparatorValueMapper: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => C,
comparator?: (valueA: C, valueB: C) => number
): T[keyof T];
/**
* Returns the minimum value in this collection. If any values are
* comparatively equivalent, the first one found will be returned.
*
* The `comparator` is used in the same way as `Iterable#sort`. If it is not
* provided, the default comparator is `<`.
*
* When two values are considered equivalent, the first encountered will be
* returned. Otherwise, `min` will operate independent of the order of input
* as long as the comparator is commutative. The default comparator `<` is
* commutative *only* when types do not differ.
*
* If `comparator` returns 0 and either value is NaN, undefined, or null,
* that value will be returned.
*/
min(comparator?: (valueA: T[keyof T], valueB: T[keyof T]) => number): T[keyof T];
/**
* Like `min`, but also accepts a `comparatorValueMapper` which allows for
* comparing by more sophisticated means:
*
* hitters.minBy(hitter => hitter.avgHits);
*
*/
minBy<C>(
comparatorValueMapper: (value?: T[keyof T], key?: keyof T, iter?: /*this*/Iterable<keyof T, T[keyof T]>) => C,
comparator?: (valueA: C, valueB: C) => number
): T[keyof T];
// Comparison
/**
* True if `iter` includes every value in this Iterable.
*/
isSubset(iter: Iterable<any, T[keyof T]>): boolean;
isSubset(iter: Array<T[keyof T]>): boolean;
/**
* True if this Iterable includes every value in `iter`.
*/
isSuperset(iter: Iterable<any, T[keyof T]>): boolean;
isSuperset(iter: Array<T[keyof T]>): boolean;
/**
* Note: this is here as a convenience to work around an issue with
* TypeScript https://github.com/Microsoft/TypeScript/issues/285, but
* Iterable does not define `size`, instead `Seq` defines `size` as
* nullable number, and `Collection` defines `size` as always a number.
*
* @ignore
*/
size: number;
}
export const MakeRecord = function<T>(value: T): TypedRecord<T> {
// Don't create a record of another record
if (Immutable.Iterable.isIterable(value)) {
return value as any;
}
let normalizedValue = {};
if (Object.getPrototypeOf(value) === Object.getPrototypeOf({})) {
normalizedValue = value;
} else {
// support anonymous classes
const propNames = [
...Object.getOwnPropertyNames(value),
...Object.getOwnPropertyNames(Object.getPrototypeOf(value)),
].filter(x => x !== "constructor");
for (const p of propNames) {
(normalizedValue as any)[p] = (value as any)[p];
}
}
const factory = Record(normalizedValue);
return new factory(normalizedValue) as any as TypedRecord<T>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment