diff --git a/src/record.js b/src/record.js index 46d61b31f..5a5ab0ea7 100644 --- a/src/record.js +++ b/src/record.js @@ -80,8 +80,8 @@ class Record { * @param {function(value: Object, key: string, record: Record)} visitor the function to apply to each field. */ forEach (visitor) { - for (let i = 0; i < this.keys.length; i++) { - visitor(this._fields[i], this.keys[i], this) + for (const [key, value] of this.entries()) { + visitor(value, key, this) } } @@ -98,13 +98,48 @@ class Record { map (visitor) { const resultArray = [] - for (let i = 0; i < this.keys.length; i++) { - resultArray.push(visitor(this._fields[i], this.keys[i], this)) + for (const [key, value] of this.entries()) { + resultArray.push(visitor(value, key, this)) } return resultArray } + /** + * Iterate over results. Each iteration will yield an array + * of exactly two items - the key, and the value (in order). + * + * @generator + * @returns {IterableIterator<[string, Object]>} + */ + * entries () { + for (let i = 0; i < this.keys.length; i++) { + yield [this.keys[i], this._fields[i]] + } + } + + /** + * Iterate over values. + * + * @generator + * @returns {IterableIterator} + */ + * values () { + for (let i = 0; i < this.keys.length; i++) { + yield this._fields[i] + } + } + + /** + * Iterate over values. Delegates to {@link Record#values} + * + * @generator + * @returns {IterableIterator} + */ + * [Symbol.iterator] () { + yield * this.values() + } + /** * Generates an object out of the current Record * @@ -112,9 +147,10 @@ class Record { */ toObject () { const object = {} - this.forEach((value, key) => { + + for (const [key, value] of this.entries()) { object[key] = value - }) + } return object } diff --git a/test/record.test.js b/test/record.test.js index e9541313c..a22fad923 100644 --- a/test/record.test.js +++ b/test/record.test.js @@ -126,4 +126,67 @@ describe('#unit Record', () => { // Then expect(result).toEqual([['Bob', 'name', record], [45, 'age', record]]) }) + + it('should allow taking values lazily', () => { + // Given + const record = new Record(['name', 'age'], ['Bob', 45]) + const values = record.values() + + // When + const first = values.next() + const second = values.next() + const third = values.next() + + // Then + expect(first.value).toEqual('Bob') + expect(first.done).toBeFalsy() + expect(second.value).toEqual(45) + expect(second.done).toBeFalsy() + expect(third.value).toBeUndefined() + expect(third.done).toBeTruthy() + }) + + it('should allow taking key-value pairs lazily', () => { + // Given + const record = new Record(['name', 'age'], ['Bob', 45]) + const entries = record.entries() + + // When + const first = entries.next() + const second = entries.next() + const third = entries.next() + + // Then + expect(first.value).toEqual(['name', 'Bob']) + expect(first.done).toBeFalsy() + expect(second.value).toEqual(['age', 45]) + expect(second.done).toBeFalsy() + expect(third.value).toBeUndefined() + expect(third.done).toBeTruthy() + }) + + it('should allow directly creating array from record', () => { + // Given + const record = new Record(['name', 'age'], ['Bob', 45]) + + // When + const values = Array.from(record) + + // Then + expect(values).toEqual(['Bob', 45]) + }) + + it('should allow iterating over values using for..of loop', () => { + // Given + const record = new Record(['name', 'age'], ['Bob', 45]) + const values = [] + + // When + for (const value of record) { + values.push(value) + } + + // Then + expect(values).toEqual(['Bob', 45]) + }) }) diff --git a/test/types/record.test.ts b/test/types/record.test.ts index ff278c7e7..15c7c36ff 100644 --- a/test/types/record.test.ts +++ b/test/types/record.test.ts @@ -37,6 +37,15 @@ record1.forEach((value: any, key: string) => {}) record1.forEach((value: any, key: string, record: Record) => {}) +const record1Entries: IterableIterator<[string, any]> = record1.entries() +const record2Entries: IterableIterator<[string, any]> = record2.entries() + +const record1Values: IterableIterator = record1.values() +const record2Values: IterableIterator = record2.values() + +const record1ToArray: any[] = [...record1] +const record2ToArray: any[] = [...record2] + const record1Has: boolean = record1.has(42) const record2Has: boolean = record1.has('key') diff --git a/types/record.d.ts b/types/record.d.ts index f4334178e..63e437a48 100644 --- a/types/record.d.ts +++ b/types/record.d.ts @@ -35,6 +35,12 @@ declare class Record { map(visitor: MapVisitor): T[] + entries(): IterableIterator<[string, Object]> + + values(): IterableIterator + + [Symbol.iterator](): IterableIterator + toObject(): object get(key: string | number): any