Skip to content

Instantly share code, notes, and snippets.

@johnfn
Created January 27, 2017 07:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnfn/898dc94fdd4bbc962d3c0ed1797835fe to your computer and use it in GitHub Desktop.
Save johnfn/898dc94fdd4bbc962d3c0ed1797835fe to your computer and use it in GitHub Desktop.
import { Iterator, Iterable, Seq, Map, OrderedMap, OrderedSet, Set, Stack, List } from 'immutable';
export type TypedRecord<T> = Readonly<T> & /* &
Immutable.Collection<keyof T, T[keyof T]>
Immutable.Iterable.Keyed<keyof T, T[keyof 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>;
// 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(): any;
/**
* 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
): V;
// 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;
}
const foobar: TypedRecord<{ a: number, b: string } = { a: 1 } as any;
const x = foobar.get('a') // x is inferred to be number
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment