diff --git a/src/errors/Messages.js b/src/errors/Messages.js
index ec74e261c..3cc5b70de 100644
--- a/src/errors/Messages.js
+++ b/src/errors/Messages.js
@@ -98,6 +98,7 @@ const Messages = {
INVALID_ELEMENT: (type, name, elem) => `Supplied ${type} ${name} includes an invalid element: ${elem}`,
MESSAGE_THREAD_PARENT: 'The message was not sent in a guild text or news channel',
+ MESSAGE_EXISTING_THREAD: 'The message already has a thread',
WEBHOOK_MESSAGE: 'The message was not sent by a webhook.',
WEBHOOK_TOKEN_UNAVAILABLE: 'This action requires a webhook token, but none is available.',
diff --git a/src/structures/Message.js b/src/structures/Message.js
index 8df623f22..118cd680a 100644
--- a/src/structures/Message.js
+++ b/src/structures/Message.js
@@ -101,16 +101,6 @@ class Message extends Base {
this.pinned = null;
}
- if ('thread' in data) {
- /**
- * The thread started by this message
- * @type {?ThreadChannel}
- */
- this.thread = this.client.channels._add(data.thread);
- } else if (!this.thread) {
- this.thread = null;
- }
-
if ('tts' in data) {
/**
* Whether or not the message was Text-To-Speech
@@ -267,6 +257,9 @@ class Message extends Base {
}
: null;
}
+ if ('thread' in data) {
+ this.client.channels._add(data.thread, this.guild);
+ }
if (this.member && data.member) {
this.member._patch(data.member);
} else if (data.member && this.guild && this.author) {
@@ -386,6 +379,26 @@ class Message extends Base {
return this.channel.guild ?? null;
}
+ /**
+ * Whether this message has a thread associated with it
+ * @type {boolean}
+ * @readonly
+ */
+ get hasThread() {
+ return this.flags.has(MessageFlags.FLAGS.HAS_THREAD);
+ }
+
+ /**
+ * The thread started by this message
+ * This property is not suitable for checking whether a message has a thread,
+ * use {@link Message#hasThread} instead.
+ * @type {?ThreadChannel}
+ * @readonly
+ */
+ get thread() {
+ return this.channel.threads.resolve(this.id);
+ }
+
/**
* The url to jump to this message
* @type {string}
@@ -726,6 +739,7 @@ class Message extends Base {
if (!['GUILD_TEXT', 'GUILD_NEWS'].includes(this.channel.type)) {
return Promise.reject(new Error('MESSAGE_THREAD_PARENT'));
}
+ if (this.hasThread) return Promise.reject(new Error('MESSAGE_EXISTING_THREAD'));
return this.channel.threads.create({ name, autoArchiveDuration, startMessage: this, reason });
}
diff --git a/typings/index.d.ts b/typings/index.d.ts
index 99f3b0f0d..8fcaebf22 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -996,6 +996,7 @@ export class Message extends Base {
public embeds: MessageEmbed[];
public groupActivityApplication: ClientApplication | null;
public readonly guild: Guild | null;
+ public readonly hasThread: boolean;
public id: Snowflake;
public interaction: MessageInteraction | null;
public readonly member: GuildMember | null;
@@ -1007,7 +1008,7 @@ export class Message extends Base {
public reactions: ReactionManager;
public stickers: Collection;
public system: boolean;
- public thread: ThreadChannel | null;
+ public readonly thread: ThreadChannel | null;
public tts: boolean;
public type: MessageType;
public readonly url: string;