In TypeScript, the Set
is a new data structure introduced in ES6, similar to Map
that allows us to store distinct values. It is similar to an array or a List but with the distinction that it doesn’t allow duplicate values.
1. Creating Set
To create a Set in TypeScript, we can simply use the Set
constructor:
const directions = new Set<string>();
To create a Set with initial values we can pass the values in an array.
const directions = new Set<string>(['east', 'west']);
2. Add, Retrieve and Delete Values from Set
set.add(v)
– adds the specified value to theSet
.set.has(v)
– checks the existence of the specified value in theSet
.set.delete(v)
– deletes the specified value from theSet
.set.clear()
– clears all the values from theSet
.set.size
– ‘size
‘ property will return the size ofSet
.
//Create a Set
let diceEntries = new Set<number>();
//Add values
diceEntries.add(1);
diceEntries.add(2);
diceEntries.add(3);
diceEntries.add(4).add(5).add(6); //Chaining of add() method is allowed
//Check value is present or not
diceEntries.has(1); //true
diceEntries.has(10); //false
//Size of Set
diceEntries.size; //6
//Delete a value from set
diceEntries.delete(6); // true
//Clear whole Set
diceEntries.clear(); //Clear all entries
3. Iterating over a Set
We can iterate over a Set using the for-of and forEach loops.
let mySet = new Set<number>();
//Added 6 entries into the set
mySet.add(1).add(2).add(3).add(4).add(5).add(6);
//Iterate over set entries
for (let currentNumber of mySet) {
console.log(currentNumber); //Prints 1 2 3 4 5 6
}
// Iterate set entries with forEach
mySet.forEach(function(value) {
console.log(value); //Prints 1 2 3 4 5 6
});
mySet.forEach(value => console.log(value)); //Prints 1 2 3 4 5 6
4. Set of Custom Types – Object Equality
By default, Sets in TypeScript use SameValueZero algorithm to determine if two objects are the same. This equality works great for simple types (string, boolean and number) but does not work with custom types.
Consider the following example where we have a Set of numbers. We added the number ‘2’ twice, but it was added only once in the Set.
const numSet = new Set<number>();
numSet.add(1).add(2).add(2);
// '2' is added only once
console.log(numSet); //{1, 2}
But, if we try to add complex types in a Set, we do not get the expected results because of how the equality is checked, by default, in ES 6.
type Person = Record<string, string>;
const personSet = new Set<Person>();
const john: Person = {
name: "John"
};
const johnDuplicate: Person = {
name: "John"
};
personSet.add(john);
personSet.add(johnDuplicate);
console.log(personSet); // Two objects are present with same content
If we want to use custom types or objects and store them in a Set, considered equal based on their content, we must manage the comparison for equality, ourselves.
Because the default equality in ES6 uses the object references, we must create a custom data structure that handles the desired object equality rules as follows:
class SetWithContentEquality<T> {
private items: T[] = [];
private getKey: (item: T) => string;
constructor(getKey: (item: T) => string) {
this.getKey = getKey;
}
add(item: T): void {
const key = this.getKey(item);
if (!this.items.some(existing => this.getKey(existing) === key)) {
this.items.push(item);
}
}
has(item: T): boolean {
return this.items.some(existing => this.getKey(existing) === this.getKey(item));
}
values(): T[] {
return [...this.items];
}
}
Now, when we store the Person objects in the Set, the two objects will be considered equal if they have the same name. It is the expected behavior in most cases.
//Compatre Person objects by their 'name' attribute
const personSet = new SetWithContentEquality<Person>(person => person.name);
const john: Person = {
name: "John"
};
const johnDuplicate: Person = {
name: "John"
};
personSet.add(john);
personSet.add(johnDuplicate);
console.log(personSet.values()); // One object with content "John"
Drop me your questions in the comments section.
Happy Learning !!
Comments