alistair
Version:
607 lines (603 loc) • 19.1 kB
text/typescript
/**
* An immutable variant of the native `Map` class where all mutating operations
* return new instances instead of modifying the original map.
*
* @template K - The type of keys in the map
* @template V - The type of values in the map
*
* @example
* ```typescript
* const map1 = new ImmutableMap([['a', 1], ['b', 2]]);
* const map2 = map1.set('c', 3);
*
* console.log(map1.get('c')); // undefined
* console.log(map2.get('c')); // 3
* ```
*/
declare class ImmutableMap<K, V> {
/**
* Internal Map instance used for storage
* @private
*/
private readonly map;
/**
* A shared empty immutable map instance. Using `never` type ensures
* it can be safely cast to ImmutableMap<K, V> for any K and V.
*
* @example
* ```typescript
* const emptyStringMap = ImmutableMap.Empty as ImmutableMap<string, number>;
* const emptyUserMap = ImmutableMap.Empty as ImmutableMap<UserId, User>;
* ```
*/
static readonly Empty: ImmutableMap<never, never>;
/**
* Creates a new ImmutableMap instance, optionally from an iterable
*
* This is perfect for usage with `useState` as React calls the `.from()` function
* when initializing the state, but TypeScript lets us set the generic types
* inline.
*
* @example
* ```typescript
* const [map, setMap] = useState(ImmutableMap.from<string, number>);
* ```
*
* @param iterable - Optional iterable of initial [key, value] pairs
* @returns A new ImmutableMap instance
*/
static from: <K_1, V_1>(iterable?: Iterable<[K_1, V_1]>) => ImmutableMap<K_1, V_1>;
/**
* Returns the number of key/value pairs in the map
*
* @example
* ```typescript
* const map = new ImmutableMap([['a', 1], ['b', 2]]);
* console.log(map.size); // 2
* ```
*/
get size(): number;
/**
* Creates a new ImmutableMap instance
*
* @param iterable - Optional iterable of initial [key, value] pairs
*
* @example
* ```typescript
* const map1 = new ImmutableMap([['a', 1], ['b', 2]]);
* const map2 = new ImmutableMap(new Map([['x', 10], ['y', 20]]));
* const empty = new ImmutableMap<string, number>();
* ```
*/
constructor(iterable?: Iterable<[K, V]>);
/**
* Creates a new map with the specified key/value pair added or updated
*
* @param key - The key to set
* @param value - The value to associate with the key
* @returns A new ImmutableMap containing the new key/value pair
*
* @example
* ```typescript
* const map1 = new ImmutableMap([['a', 1]]);
* const map2 = map1.set('b', 2);
* const map3 = map2.set('a', 10); // Updates existing key
*
* console.log(map1.get('b')); // undefined
* console.log(map2.get('b')); // 2
* console.log(map3.get('a')); // 10
* ```
*/
set(key: K, value: V): ImmutableMap<K, V>;
/**
* Retrieves the value associated with a key
*
* @param key - The key to look up
* @returns The value associated with the key, or undefined if the key doesn't exist
*
* @example
* ```typescript
* const map = new ImmutableMap([['a', 1], ['b', 2]]);
* console.log(map.get('a')); // 1
* console.log(map.get('x')); // undefined
* ```
*/
get(key: K): V | undefined;
/**
* Checks if a key exists in the map
*
* @param key - The key to check
* @returns `true` if the key exists, `false` otherwise
*
* @example
* ```typescript
* const map = new ImmutableMap([['a', 1], ['b', 2]]);
* console.log(map.has('a')); // true
* console.log(map.has('x')); // false
* ```
*/
has(key: K): boolean;
/**
* Creates a new map with the specified key removed
*
* @param key - The key to remove
* @returns A new ImmutableMap with the key/value pair removed
*
* @example
* ```typescript
* const map1 = new ImmutableMap([['a', 1], ['b', 2]]);
* const map2 = map1.delete('a');
*
* console.log(map1.has('a')); // true
* console.log(map2.has('a')); // false
* ```
*/
delete(key: K): ImmutableMap<K, V>;
/**
* Creates a new empty map
*
* @returns A new empty ImmutableMap
*
* @example
* ```typescript
* const map1 = new ImmutableMap([['a', 1], ['b', 2]]);
* const map2 = map1.clear();
*
* console.log(map1.size); // 2
* console.log(map2.size); // 0
* ```
*/
clear(): ImmutableMap<K, V>;
/**
* Executes a callback for each key/value pair in the map
*
* @param callbackfn - Function to execute for each entry
* @param thisArg - Value to use as `this` when executing the callback
*
* @example
* ```typescript
* const map = new ImmutableMap([['a', 1], ['b', 2]]);
* const results: string[] = [];
* map.forEach((value, key) => {
* results.push(`${key}=${value}`);
* });
* console.log(results); // ['a=1', 'b=2']
* ```
*/
forEach(callbackfn: (value: V, key: K) => void, thisArg?: any): void;
/**
* Returns an iterator of the map's keys
*
* @returns An iterator containing the keys
*
* @example
* ```typescript
* const map = new ImmutableMap([['a', 1], ['b', 2]]);
* const keys = [...map.keys()];
* console.log(keys); // ['a', 'b']
* ```
*/
keys(): IterableIterator<K>;
/**
* Returns an iterator of the map's values
*
* @returns An iterator containing the values
*
* @example
* ```typescript
* const map = new ImmutableMap([['a', 1], ['b', 2]]);
* const values = [...map.values()];
* console.log(values); // [1, 2]
* ```
*/
values(): IterableIterator<V>;
/**
* Returns an iterator of the map's entries
*
* @returns An iterator containing [key, value] pairs
*
* @example
* ```typescript
* const map = new ImmutableMap([['a', 1], ['b', 2]]);
* for (const [key, value] of map.entries()) {
* console.log(`${key}=${value}`); // Logs: 'a=1', then 'b=2'
* }
* ```
*/
entries(): IterableIterator<[K, V]>;
/**
* Implements the iterable protocol, allowing the map to be used with for...of loops
*
* @returns An iterator containing [key, value] pairs
*
* @example
* ```typescript
* const map = new ImmutableMap([['a', 1], ['b', 2]]);
* for (const [key, value] of map) {
* console.log(`${key}=${value}`); // Logs: 'a=1', then 'b=2'
* }
* ```
*/
[Symbol.iterator](): IterableIterator<[K, V]>;
/**
* Customizes the string tag for the ImmutableMap instance
* Used in Object.prototype.toString.call(immutableMap)
*
* @example
* ```typescript
* const map = new ImmutableMap();
* console.log(Object.prototype.toString.call(map)); // '[object ImmutableMap]'
* ```
*/
get [Symbol.toStringTag](): string;
/**
* Internal helper method for creating new instances when performing
* mutations. This ensures immutability while allowing reuse of logic.
*
* @param fn - Function that performs the mutation on the cloned map
* @returns A new ImmutableMap instance with the mutation applied
* @private
*/
private mutate;
}
/**
* An immutable variant of the native `Set` class where all mutating operations
* return new instances instead of modifying the original set.
*
* @template T - The type of elements in the set
*
* @example
* ```typescript
* const set1 = new ImmutableSet(['a', 'b']);
* const set2 = set1.add('c');
*
* console.log([...set1]); // ['a', 'b']
* console.log([...set2]); // ['a', 'b', 'c']
* ```
*/
declare class ImmutableSet<T> {
/**
* Internal Set instance used for storage
* @private
*/
private readonly set;
/**
* A shared empty immutable set instance. Using `never` type ensures
* it can be safely cast to ImmutableSet<T> for any T.
*
* @example
* ```typescript
* const emptyStrings = ImmutableSet.Empty as ImmutableSet<string>;
* const emptyNumbers = ImmutableSet.Empty as ImmutableSet<number>;
* ```
*
* You can also use this
*/
static readonly Empty: ImmutableSet<never>;
/**
* Creates a new ImmutableSet instance, optionally from an iterable
*
* This is perfect for usage with `useState` as React calls the `.from()` function
* when initializing the state, but TypeScript lets us set the generic type
* inline.
*
* ```typescript
* const [set, setState] = useState(ImmutableSet.from<string>);
* ```
*
* @param iterable - Optional iterable of initial values
* @returns A new ImmutableSet instance
*/
static from: <T_1>(iterable?: Iterable<T_1>) => ImmutableSet<T_1>;
/**
* Creates a new ImmutableSet instance
*
* @param iterable - Optional iterable of initial values
*
* @example
* ```typescript
* const set1 = new ImmutableSet(['a', 'b', 'c']);
* const set2 = new ImmutableSet(new Set([1, 2, 3]));
* const empty = new ImmutableSet<string>();
* ```
*/
constructor(iterable?: Iterable<T>);
/**
* Internal helper method for creating new instances when performing
* mutations. This ensures immutability while allowing reuse of logic.
*
* @param fn - Function that performs the mutation on the cloned set
* @returns A new ImmutableSet instance with the mutation applied
* @private
*/
private mutate;
/**
* Creates a new set with the specified value added
*
* @param value - The value to add
* @returns A new ImmutableSet containing the added value
*
* @example
* ```typescript
* const set1 = new ImmutableSet(['a', 'b']);
* const set2 = set1.add('c');
* console.log([...set2]); // ['a', 'b', 'c']
* console.log(set1 === set2); // false
* ```
*/
add(value: T): ImmutableSet<T>;
/**
* Creates a new empty set, discarding all current values
*
* @returns The empty ImmutableSet singleton instance
*
* @example
* ```typescript
* const set1 = new ImmutableSet(['a', 'b']);
* const set2 = set1.clear();
* console.log(set2.size); // 0
* console.log(set2 === ImmutableSet.Empty); // true
* ```
*/
clear(): ImmutableSet<never>;
/**
* Creates a new set with the specified value removed
*
* @param value - The value to remove
* @returns A new ImmutableSet with the value removed
*
* @example
* ```typescript
* const set1 = new ImmutableSet(['a', 'b', 'c']);
* const set2 = set1.delete('b');
* console.log([...set2]); // ['a', 'c']
* console.log(set1.has('b')); // true
* ```
*/
delete(value: T): ImmutableSet<T>;
/**
* Executes a callback for each value in the set
*
* @param callbackfn - Function to execute for each value
* @param thisArg - Value to use as `this` when executing the callback
*
* @example
* ```typescript
* const set = new ImmutableSet(['a', 'b', 'c']);
* const results: string[] = [];
* set.forEach(value => results.push(value.toUpperCase()));
* console.log(results); // ['A', 'B', 'C']
* ```
*/
forEach(callbackfn: (value: T, value2: T) => void, thisArg?: unknown): void;
/**
* Toggles a value in the set, adding it if it doesn't exist or removing it if it does
*
* @param value - The value to toggle
* @returns A new ImmutableSet with the value toggled
*
* @example
* ```typescript
* const set = new ImmutableSet(['a', 'b']);
* const set2 = set.toggle('c');
* console.log([...set2]); // ['a', 'b', 'c']
* ```
*
* This is super helpful with React state management because the methods return a new instance
* and it means React knows the state has changed.
*
* ```tsx
* const [state, setState] = useState(ImmutableSet.from<string>)
* <button onClick={() => setState(old => old.toggle('c'))}>Toggle c</button>
* ```
*/
toggle(value: T): ImmutableSet<T>;
/**
* Checks if a value exists in the set
*
* @param value - The value to check
* @returns `true` if the value exists, `false` otherwise
*
* @example
* ```typescript
* const set = new ImmutableSet(['a', 'b']);
* console.log(set.has('a')); // true
* console.log(set.has('c')); // false
* ```
*/
has(value: T): boolean;
/**
* Returns an iterator of [value, value] pairs
*
* @returns An iterator containing pairs of values
*
* @example
* ```typescript
* const set = new ImmutableSet(['a', 'b']);
* for (const [value1, value2] of set.entries()) {
* console.log(value1 === value2); // true
* }
* ```
*/
entries(): SetIterator<[T, T]>;
/**
* Returns an iterator of values (identical to values())
*
* @returns An iterator containing the values
*
* @example
* ```typescript
* const set = new ImmutableSet(['a', 'b']);
* const keys = [...set.keys()];
* console.log(keys); // ['a', 'b']
* ```
*/
keys(): SetIterator<T>;
/**
* Returns an iterator of values
*
* @returns An iterator containing the values
*
* @example
* ```typescript
* const set = new ImmutableSet(['a', 'b']);
* const values = [...set.values()];
* console.log(values); // ['a', 'b']
* ```
*/
values(): SetIterator<T>;
/**
* Implements the iterable protocol, allowing the set to be used with for...of loops
*
* @returns An iterator containing the values
*
* @example
* ```typescript
* const set = new ImmutableSet(['a', 'b']);
* for (const value of set) {
* console.log(value); // 'a', then 'b'
* }
* ```
*/
[Symbol.iterator](): SetIterator<T>;
/**
* Customizes the string tag for the ImmutableSet instance
* Used in Object.prototype.toString.call(immutableSet)
*
* @example
* ```typescript
* const set = new ImmutableSet();
* console.log(Object.prototype.toString.call(set)); // '[object ImmutableSet]'
* ```
*/
get [Symbol.toStringTag](): string;
/**
* Returns the number of values in the set
*
* @example
* ```typescript
* const set = new ImmutableSet(['a', 'b']);
* console.log(set.size); // 2
* ```
*/
get size(): number;
}
/**
* A strict variant of the native `Map` class that enforces explicit handling of missing keys.
* Unlike the standard Map, this implementation requires specifying default value behavior
* when accessing potentially missing keys.
*
* @template K - The key type
* @template V - The value type
*
* @example
* ```typescript
* const map = new StrictMap<string, number>();
*
* // Inserting a value if it doesn't exist
* const value = map.getOr('key', () => 42); // 42
*
* // Subsequent access returns the stored value
* const sameValue = map.getOr('key', () => 100); // 42
*
* // Using getElse for optional access
* const optional = map.getElse('missing', () => null); // null
* ```
*/
declare class StrictMap<K, V> {
/**
* Internal Map instance used for storage
* @private
*/
private readonly map;
/**
* Returns the number of key/value pairs in the StrictMap
*/
get size(): number;
/**
* Customizes the string tag for the StrictMap instance
* Used in Object.prototype.toString.call(strictMap)
*/
get [Symbol.toStringTag](): string;
/**
* Removes all key/value pairs from the StrictMap
*/
clear(): void;
/**
* Removes the specified key and its associated value
* @param key - The key to remove
* @returns `true` if the key existed and was removed, `false` otherwise
*/
delete(key: K): boolean;
/**
* Executes the provided callback for each key/value pair
* @param callbackfn - Function to execute for each entry
* @param thisArg - Value to use as `this` when executing the callback
*/
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
/**
* Retrieves the value for a key, or inserts and returns a new value if the key doesn't exist.
* This is the primary method for accessing values, as it ensures all keys have an associated value.
*
* @param key - The key to lookup
* @param or - Factory function that produces the default value if the key doesn't exist
* @returns The existing value or the newly inserted default value
*
* @example
* ```typescript
* const map = new StrictMap<string, string[]>();
* const value = map.getOr('users', () => []); // Creates new array if 'users' doesn't exist
* value.push('user1'); // Safe to use, we know it's an array
* ```
*/
getOr(key: K, or: () => V): V;
/**
* Similar to `getOr`, but allows returning a different type when the key doesn't exist.
* This is useful for optional access patterns where you don't want to insert a default value.
*
* @param key - The key to lookup
* @param or - Factory function that produces the alternative value if the key doesn't exist
* @returns The existing value of type V, or the alternative value of type N
*
* @example
* ```typescript
* const map = new StrictMap<string, number>();
* const value = map.getElse('count', () => null); // Returns null if key doesn't exist
* ```
*/
getElse<N>(key: K, or: () => N): V | N;
/**
* Checks if the specified key exists
* @param key - The key to check
* @returns `true` if the key exists, `false` otherwise
*/
has(key: K): boolean;
/**
* Sets a key/value pair in the map
* @param key - The key to set
* @param value - The value to associate with the key
* @returns The StrictMap instance for method chaining
*/
set(key: K, value: V): this;
/**
* Returns an iterator of key/value pairs
* @returns An iterator containing [key, value] pairs
*/
entries(): IterableIterator<[K, V]>;
/**
* Returns an iterator of keys
* @returns An iterator containing the keys
*/
keys(): IterableIterator<K>;
/**
* Returns an iterator of values
* @returns An iterator containing the values
*/
values(): IterableIterator<V>;
/**
* Implements the iterable protocol, allowing the StrictMap to be used with for...of loops
* @returns An iterator containing [key, value] pairs
*/
[Symbol.iterator](): IterableIterator<[K, V]>;
}
export { ImmutableMap, ImmutableSet, StrictMap };