Skip to main content

How to Use TypeScript Set

TypeScript's Set offers a built-in way to store unique values and perform common collection operations. This article walks through everything you need to work with Sets effectively: creating and modifying Sets, checking for element existence, iterating through elements, converting between Sets and arrays, and handling Set comparisons. You'll learn practical patterns for managing collections where duplicates aren't allowed, like unique user IDs, tags, or configuration options.

Initializing and Filling a Set

The TypeScript Set constructor lets you create Sets in two ways: empty Sets for adding elements later, or pre-filled Sets from existing arrays. When initializing from an array, duplicates are automatically removed - a key feature that makes Sets useful for deduplication tasks.

// Empty set with type annotation
const emptySet = new Set<string>();

// Pre-filled set from array
const numbers = new Set([1, 2, 3, 4, 4, 5]); // duplicates are removed
console.log(numbers.size); // Output: 5

// Set with mixed types
const mixedSet = new Set<string | number>(['a', 1, 'b', 2]);

Adding, Removing, and Checking Items

Add items to a Set with the add() method, remove items with the delete() method, and check if a Set contains an item with the has() method.

// Create a Set with type safety
const uniqueNumbers = new Set<number>([1, 2, 3]);

// Add elements
uniqueNumbers.add(4);
console.log(uniqueNumbers.size); // Output: 4

// Remove elements
uniqueNumbers.delete(2);
console.log(uniqueNumbers.size); // Output: 3

// Check if an element exists
console.log(uniqueNumbers.has(3)); // Output: true

// Adding duplicates has no effect
uniqueNumbers.add(3);
console.log(uniqueNumbers.size); // Output: 3

Going Through a Set

To go through a Set, use the forEach() method or turn the Set into an array with the spread operator.

// Create a typed Set
const uniqueNumbers = new Set<number>([1, 2, 3]);

// Using forEach
uniqueNumbers.forEach((value) => {
console.log(value);
});

// Using for...of loop
for (const value of uniqueNumbers) {
console.log(value); // Outputs: 1, 2, 3
}

// Convert to array and iterate
const array = [...uniqueNumbers];
console.log(array); // Output: [1, 2, 3]

Turning a Set into an Array

TypeScript provides two straightforward ways to convert Sets to arrays: the spread operator (...) and Array.from(). Both methods work equally well with typed Sets.

// Initialize a typed Set
const uniqueNumbers = new Set<number>([1, 2, 3]);

// Using spread operator
const arrayFromSpread = [...uniqueNumbers];
console.log(arrayFromSpread); // Output: [1, 2, 3]

// Using Array.from()
const arrayFromMethod = Array.from(uniqueNumbers);
console.log(arrayFromMethod); // Output: [1, 2, 3]

// Useful for chaining array methods
const doubledNumbers = [...uniqueNumbers].map(n => n * 2);
console.log(doubledNumbers); // Output: [2, 4, 6]

Comparing Sets

To compare two Sets, find their union, intersection, or difference. These operations create new Sets while preserving type safety. These operations often use filter methods to create new Sets while preserving type safety.

// Create typed Sets
const setA = new Set<number>([1, 2, 3]);
const setB = new Set<number>([3, 4, 5]);

// Union: combine all unique elements
const union = new Set([...setA, ...setB]);
console.log([...union]); // Output: [1, 2, 3, 4, 5]

// Intersection: elements present in both sets
const intersection = new Set([...setA].filter(value => setB.has(value)));
console.log([...intersection]); // Output: [3]

// Difference: elements in setA that aren't in setB
const difference = new Set([...setA].filter(value => !setB.has(value)));
console.log([...difference]); // Output: [1, 2]

// Check if a Set is a subset of another
const isSubset = [...setA].every(value => setB.has(value));
console.log(isSubset); // Output: false

Clearing a Set

To remove all items from a Set, use the clear() method. This operation maintains the Set's type while emptying its contents.

// Create a typed Set
const uniqueNumbers = new Set<number>([1, 2, 3]);

// Remove all elements
uniqueNumbers.clear();
console.log(uniqueNumbers.size); // Output: 0

// The Set maintains its type after clearing
uniqueNumbers.add(4); // Still type-safe

Working with Complex Types in Sets

TypeScript Sets can store objects and custom types, but they require careful handling for comparison and deduplication. When working with Sets of objects in a database context, you might want to explore Convex's powerful filtering capabilities for more efficient data handling.

// Sets with objects need careful comparison
type User = { id: number; name: string };
const userSet = new Set<User>();

// Objects with same content are considered different
userSet.add({ id: 1, name: "Alice" });
userSet.add({ id: 1, name: "Alice" }); // This adds a duplicate!
console.log(userSet.size); // Output: 2

// Better: Store references or use id as key
const userMap = new Map<number, User>();
userMap.set(1, { id: 1, name: "Alice" });
userMap.set(1, { id: 1, name: "Alice" }); // No duplicate

Real-World Applications

Sets excel at tasks like tracking unique values, managing state changes, and filtering duplicates from data streams. They're particularly useful with TypeScript's utility types for type-safe data manipulation.

// Tracking unique form field changes
const changedFields = new Set<keyof UserForm>();
changedFields.add('email');
changedFields.add('password');

// Filtering unique values from an API response
interface ApiResponse {
tags: string[];
}
const uniqueTags = new Set(apiResponse.tags);

While Sets work well for tracking state changes, consider Convex as a more robust alternative to useState for production applications that need persistent state management.

Using TypeScript Sets Effectively

TypeScript Sets solve common programming challenges around unique value management while providing compile-time type safety. They work seamlessly with Map<K, V> types for key-value relationships and integrate well with utility types for data transformation. When working with collections in TypeScript, Sets are your go-to tool for handling unique values, whether you're managing user IDs, filtering API responses, or tracking state changes. For more complex data relationships, explore Record<K, V> types or other TypeScript collection options. For full-stack applications, leverage Convex's TypeScript integration to build type-safe data operations.