diff --git a/src/structures/ThreadChannel.js b/src/structures/ThreadChannel.js index 40d4bab57bde..1f977285ee50 100644 --- a/src/structures/ThreadChannel.js +++ b/src/structures/ThreadChannel.js @@ -100,6 +100,11 @@ class ThreadChannel extends Channel { * @type {?number} */ this.archiveTimestamp = new Date(data.thread_metadata.archive_timestamp).getTime(); + + if ('create_timestamp' in data.thread_metadata) { + // Note: this is needed because we can't assign directly to getters + this._createdTimestamp = Date.parse(data.thread_metadata.create_timestamp); + } } else { this.locked ??= null; this.archived ??= null; @@ -108,6 +113,8 @@ class ThreadChannel extends Channel { this.invitable ??= null; } + this._createdTimestamp ??= this.type === 'GUILD_PRIVATE_THREAD' ? super.createdTimestamp : null; + if ('owner_id' in data) { /** * The id of the member who created this thread @@ -176,6 +183,16 @@ class ThreadChannel extends Channel { if (data.messages) for (const message of data.messages) this.messages._add(message); } + /** + * The timestamp when this thread was created. This isn't available for threads + * created before 2022-01-09 + * @type {?number} + * @readonly + */ + get createdTimestamp() { + return this._createdTimestamp; + } + /** * A collection of associated guild member objects of this thread's members * @type {Collection} @@ -196,6 +213,15 @@ class ThreadChannel extends Channel { return new Date(this.archiveTimestamp); } + /** + * The time the thread was created at + * @type {?Date} + * @readonly + */ + get createdAt() { + return this.createdTimestamp && new Date(this.createdTimestamp); + } + /** * The parent channel of this thread * @type {?(NewsChannel|TextChannel)} @@ -490,6 +516,14 @@ class ThreadChannel extends Channel { return this.archived && this.sendable && (!this.locked || this.manageable); } + /** + * Whether this thread is a private thread + * @returns {boolean} + */ + isPrivate() { + return this.type === 'GUILD_PRIVATE_THREAD'; + } + /** * Deletes this thread. * @param {string} [reason] Reason for deleting this thread diff --git a/typings/index.d.ts b/typings/index.d.ts index 8219cb15f696..6d82cf002abb 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -516,8 +516,8 @@ export type CategoryChannelResolvable = Snowflake | CategoryChannel; export abstract class Channel extends Base { public constructor(client: Client, data?: RawChannelData, immediatePatch?: boolean); - public readonly createdAt: Date; - public readonly createdTimestamp: number; + public readonly createdAt: Date | null; + public readonly createdTimestamp: number | null; /** @deprecated This will be removed in the next major version, see https://github.com/discordjs/discord.js/issues/7091 */ public deleted: boolean; public id: Snowflake; @@ -1042,7 +1042,8 @@ export abstract class GuildChannel extends Channel { public constructor(guild: Guild, data?: RawGuildChannelData, client?: Client, immediatePatch?: boolean); private memberPermissions(member: GuildMember, checkAdmin: boolean): Readonly; private rolePermissions(role: Role, checkAdmin: boolean): Readonly; - + public readonly createdAt: Date; + public readonly createdTimestamp: number; public readonly calculatedPosition: number; public readonly deletable: boolean; public guild: Guild; @@ -2305,6 +2306,9 @@ export class ThreadChannel extends TextBasedChannelMixin(Channel) { public archived: boolean | null; public readonly archivedAt: Date | null; public archiveTimestamp: number | null; + public readonly createdAt: Date | null; + private _createdTimestamp: number | null; + public readonly createdTimestamp: number | null; public autoArchiveDuration: ThreadAutoArchiveDuration | null; public readonly editable: boolean; public guild: Guild; @@ -2328,6 +2332,11 @@ export class ThreadChannel extends TextBasedChannelMixin(Channel) { public rateLimitPerUser: number | null; public type: ThreadChannelTypes; public readonly unarchivable: boolean; + public isPrivate(): this is this & { + readonly createdTimestamp: number; + readonly createdAt: Date; + type: 'GUILD_PRIVATE_THREAD'; + }; public delete(reason?: string): Promise; public edit(data: ThreadEditData, reason?: string): Promise; public join(): Promise;