Repository: discordjs/discord.js
File: packages/collection/src/collection.ts (TypeScript)

Code before:
/* eslint-disable no-param-reassign */

/**
 * Represents an immutable version of a collection
 */
export type ReadonlyCollection<Key, Value> = Omit<
	Collection<Key, Value>,
	'clear' | 'delete' | 'ensure' | 'forEach' | 'get' | 'reverse' | 'set' | 'sort' | 'sweep'
> &
	ReadonlyMap<Key, Value>;

export interface Collection<Key, Value> {
	/**
	 * Ambient declaration to allow references to `this.constructor` in class methods.
	 *
	 * @internal
	 */
	constructor: typeof Collection;
}

/**
 * A Map with additional utility methods. This is used throughout discord.js rather than Arrays for anything that has
 * an ID, for significantly improved performance and ease-of-use.
 *
 * @typeParam Key - The key type this collection holds
 * @typeParam Value - The value type this collection holds
 */
export class Collection<Key, Value> extends Map<Key, Value> {
	/**
	 * @internal
	 */
	declare public static readonly [Symbol.species]: typeof Collection;

	/**
	 * Obtains the value of the given key if it exists, otherwise sets and returns the value provided by the default value generator.
	 *
	 * @param key - The key to get if it exists, or set otherwise
	 * @param defaultValueGenerator - A function that generates the default value
	 * @example
	 * ```ts
	 * collection.ensure(guildId, () => defaultGuildConfig);
	 * ```
	 */
	public ensure(key: Key, defaultValueGenerator: (key: Key, collection: this) => Value): Value {

Review comment (suggestion):
In-class `declare` syntax specifically balks at a property named `constructor`, so this declaration has to remain in its own interface rather than being merged into the class body.

Code after:
/* eslint-disable no-param-reassign */

/**
 * Represents an immutable version of a collection
 */
export type ReadonlyCollection<Key, Value> = Omit<
	Collection<Key, Value>,
	'clear' | 'delete' | 'ensure' | 'forEach' | 'get' | 'reverse' | 'set' | 'sort' | 'sweep'
> &
	ReadonlyMap<Key, Value>;

export interface Collection<Key, Value> {
	/**
	 * Ambient declaration to allow references to `this.constructor` in class methods.
	 *
	 * @internal
	 */
	constructor: typeof Collection;
}

/**
 * A Map with additional utility methods. This is used throughout discord.js rather than Arrays for anything that has
 * an ID, for significantly improved performance and ease-of-use.
 *
 * @typeParam Key - The key type this collection holds
 * @typeParam Value - The value type this collection holds
 */
export class Collection<Key, Value> extends Map<Key, Value> {
	/**
	 * Obtains the value of the given key if it exists, otherwise sets and returns the value provided by the default value generator.
	 *
	 * @param key - The key to get if it exists, or set otherwise
	 * @param defaultValueGenerator - A function that generates the default value
	 * @example
	 * ```ts
	 * collection.ensure(guildId, () => defaultGuildConfig);
	 * ```
	 */
	public ensure(key: Key, defaultValueGenerator: (key: Key, collection: this) => Value): Value {
		if (this.has(key)) return this.get(key)!;
		if (typeof defaultValueGenerator !== 'function') throw new TypeError(`${defaultValueGenerator} is not a function`);
		const defaultValue = defaultValueGenerator(key, this);
		this.set(key, defaultValue);
		return defaultValue;