Repository: discordjs/discord.js
File: packages/structures/src/subscriptions/Subscription.ts (TypeScript)

Code before:
import { DiscordSnowflake } from '@sapphire/snowflake';
import type { APISubscription, SubscriptionStatus } from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import {
	kData,
	kCurrentPeriodStartTimestamp,
	kCurrentPeriodEndTimestamp,
	kCanceledTimestamp,
} from '../utils/symbols.js';
import { isIdSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';

/**
 * Represents any subscription on Discord.
 *
 * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
 * @remarks intentionally does not export `skuIds`, `entitlementIds`, and `renewalSkuIds` so that extending classes can resolve
 * `Snowflake[]` to `SKU[]`, `Entitlement[]`, and `?SKU[]`, respectively
 */
export class Subscription<
	Omitted extends keyof APISubscription | '' = 'current_period_end' | 'current_period_start',
> extends Structure<APISubscription, Omitted> {
	/**
	 * The template used for removing data from the raw data stored for each subscription
	 */
	public static override readonly DataTemplate: Partial<APISubscription> = {
		set current_period_start(_: string) {},
		set current_period_end(_: string) {},
	};

	protected [kCurrentPeriodStartTimestamp]: number | null = null;

	protected [kCurrentPeriodEndTimestamp]: number | null = null;

	protected [kCanceledTimestamp]: number | null = null;

	/**
	 * @param data - The raw data received from the API for the subscription
	 */
	public constructor(data: Partialize<APISubscription, Omitted>) {
		super(data);
		this.optimizeData(data);
	}

Review comment (suggestion):
Considering those fields are named with the `Ids` suffix I'd say we should expose them as getters returning readonly arrays.  Extending classes would then expose the full structures as `skus`, `entitlements` and `renewalSkus`.

Code after:
import { DiscordSnowflake } from '@sapphire/snowflake';
import type { APISubscription, SubscriptionStatus } from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import {
	kData,
	kCurrentPeriodStartTimestamp,
	kCurrentPeriodEndTimestamp,
	kCanceledTimestamp,
} from '../utils/symbols.js';
import { isIdSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';

/**
 * Represents any subscription on Discord.
 *
 * @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
 */
export class Subscription<
	Omitted extends keyof APISubscription | '' = 'canceled_at' | 'current_period_end' | 'current_period_start',
> extends Structure<APISubscription, Omitted> {
	/**
	 * The template used for removing data from the raw data stored for each subscription
	 */
	public static override readonly DataTemplate: Partial<APISubscription> = {
		set current_period_start(_: string) {},
		set current_period_end(_: string) {},
		set canceled_at(_: string) {},
	};

	protected [kCurrentPeriodStartTimestamp]: number | null = null;

	protected [kCurrentPeriodEndTimestamp]: number | null = null;

	protected [kCanceledTimestamp]: number | null = null;

	/**
	 * @param data - The raw data received from the API for the subscription
	 */
	public constructor(data: Partialize<APISubscription, Omitted>) {
		super(data);
		this.optimizeData(data);
	}