Set.prototype.keys()
set.keys() The keys() method returns a new Set Iterator object that contains the values for each element in the set, in insertion order. Introduced in ES2015, this method exists primarily for consistency with the Map object’s API.
Syntax
set.keys()
Return Value
A new Set Iterator object. The iterator yields the values (not keys, despite the method name) in the order they were inserted into the set.
Why Both keys() and values()?
Here’s the surprising part: Setkeys() is functionally identical to Setvalues(). They return exactly the same iterator.
This redundancy exists for API consistency with the Map object. When working with both Maps and Sets, it’s convenient to have a uniform interface:
| Object | keys() | values() | entries() |
|---|---|---|---|
| Map | Returns keys | Returns values | Returns [key, value] pairs |
| Set | Returns values* | Returns values | Returns [value, value] pairs |
*In a Set, there’s no meaningful distinction between keys and values—all elements are values. The keys() method exists purely for symmetry with Map.
Set vs Map: the key difference
While Mapkeys() returns the actual keys of a Map, Setkeys() returns the Set’s values (since Sets don’t have keys):
// Map - keys() returns actual keys
const map = new Map([['a', 1], ['b', 2]]);
console.log([...map.keys()]); // ['a', 'b']
// Set - keys() returns values (same as values())
const set = new Set(['a', 'b', 'c']);
console.log([...set.keys()]); // ['a', 'b', 'c']
console.log([...set.values()]); // ['a', 'b', 'c'] - identical!
The keys() method follows the same iterator protocol as values() and entries(), so you can use it with for...of, the spread operator, and manual next() calls. The following examples show each of these patterns applied to Set iteration through keys().
Examples
Basic iteration with for…of
The most common way to iterate over a Set’s values:
const colors = new Set(['red', 'green', 'blue']);
for (const color of colors.keys()) {
console.log(color);
}
// Output:
// red
// green
// blue
A for...of loop hides the iterator mechanics, but calling next() directly reveals what’s happening under the hood. Each call advances the internal cursor, and the returned object carries both the current value and a done flag that signals exhaustion.
Manual iteration with next()
Fine-grained control using the iterator protocol:
const numbers = new Set([10, 20, 30]);
const iterator = numbers.keys();
iterator.next(); // { value: 10, done: false }
iterator.next(); // { value: 20, done: false }
iterator.next(); // { value: 30, done: false }
iterator.next(); // { value: undefined, done: true }
Since keys() and values() are functionally identical for Sets, you can confirm this by comparing their output side by side. The example below creates separate iterators from both methods and shows they produce the same sequence.
Proving keys() is identical to values()
This example demonstrates that both methods return the same result:
const set = new Set([1, 2, 3]);
const keysIterator = set.keys();
const valuesIterator = set.values();
// They are the same object type
console.log(keysIterator[Symbol.toStringTag]); // 'Set Iterator'
// Same sequence of values
console.log(keysIterator.next().value); // 1
console.log(valuesIterator.next().value); // 1
// Can be used interchangeably
console.log([...set.keys()]); // [1, 2, 3]
console.log([...set.values()]); // [1, 2, 3]
When to Use
- API consistency: Use
keys()when you want uniform code between Map and Set handling - Explicit intent: Some developers prefer
keys()to signal “iterating the set” - Modern iteration: Works with
for...ofand spread operator
For most use cases, values() is clearer since it accurately describes what’s being returned.
Why keys() still exists
The method remains in the API because Sets mirror Map in the iterator methods they expose. That symmetry makes generic collection code easier to write, especially when a helper might work with either structure. Even though the name says keys(), the return value is still the set’s values, so it is more of a compatibility hook than a unique feature. In practice, that means the method is useful when you want to preserve a common interface rather than because it adds new behavior.
Choosing between keys() and values()
Most code should prefer values() because it says what the iterator actually yields. keys() can still be handy when you are writing collection-agnostic code or porting logic from a Map workflow where keys() is the primary operation. The important thing is to remember that the two methods produce the same iterator sequence for Sets, so choosing one over the other is about readability, not output.
See Also
- Set.prototype.values() - Returns a Set Iterator (functionally identical)
- Set.prototype.entries() - Returns [value, value] pairs
- Map.prototype.keys() - Returns actual map keys