types(MessageManager): Allow comparison of messages again (#9612)

* types(MessageManager): allow comparison of messages again

* feat: match TypeScript

* docs: update wording

* chore: revert breaking change

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Jiralite
2023-07-07 22:39:01 +01:00
committed by GitHub
parent a73d54e43a
commit a48d0efb09
11 changed files with 98 additions and 32 deletions

View File

@@ -55,6 +55,7 @@ exports.CachedManager = require('./managers/CachedManager');
exports.ChannelManager = require('./managers/ChannelManager'); exports.ChannelManager = require('./managers/ChannelManager');
exports.ClientVoiceManager = require('./client/voice/ClientVoiceManager'); exports.ClientVoiceManager = require('./client/voice/ClientVoiceManager');
exports.DataManager = require('./managers/DataManager'); exports.DataManager = require('./managers/DataManager');
exports.DMMessageManager = require('./managers/DMMessageManager');
exports.GuildApplicationCommandManager = require('./managers/GuildApplicationCommandManager'); exports.GuildApplicationCommandManager = require('./managers/GuildApplicationCommandManager');
exports.GuildBanManager = require('./managers/GuildBanManager'); exports.GuildBanManager = require('./managers/GuildBanManager');
exports.GuildChannelManager = require('./managers/GuildChannelManager'); exports.GuildChannelManager = require('./managers/GuildChannelManager');
@@ -65,6 +66,7 @@ exports.GuildInviteManager = require('./managers/GuildInviteManager');
exports.GuildManager = require('./managers/GuildManager'); exports.GuildManager = require('./managers/GuildManager');
exports.GuildMemberManager = require('./managers/GuildMemberManager'); exports.GuildMemberManager = require('./managers/GuildMemberManager');
exports.GuildMemberRoleManager = require('./managers/GuildMemberRoleManager'); exports.GuildMemberRoleManager = require('./managers/GuildMemberRoleManager');
exports.GuildMessageManager = require('./managers/GuildMessageManager');
exports.GuildScheduledEventManager = require('./managers/GuildScheduledEventManager'); exports.GuildScheduledEventManager = require('./managers/GuildScheduledEventManager');
exports.GuildStickerManager = require('./managers/GuildStickerManager'); exports.GuildStickerManager = require('./managers/GuildStickerManager');
exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager'); exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager');

View File

@@ -0,0 +1,17 @@
'use strict';
const MessageManager = require('./MessageManager');
/**
* Manages API methods for messages in direct message channels and holds their cache.
* @extends {MessageManager}
*/
class DMMessageManager extends MessageManager {
/**
* The channel that the messages belong to
* @name DMMessageManager#channel
* @type {DMChannel}
*/
}
module.exports = DMMessageManager;

View File

@@ -0,0 +1,17 @@
'use strict';
const MessageManager = require('./MessageManager');
/**
* Manages API methods for messages in a guild and holds their cache.
* @extends {MessageManager}
*/
class GuildMessageManager extends MessageManager {
/**
* The channel that the messages belong to
* @name GuildMessageManager#channel
* @type {GuildTextBasedChannel}
*/
}
module.exports = GuildMessageManager;

View File

@@ -12,6 +12,7 @@ const { resolvePartialEmoji } = require('../util/Util');
/** /**
* Manages API methods for Messages and holds their cache. * Manages API methods for Messages and holds their cache.
* @extends {CachedManager} * @extends {CachedManager}
* @abstract
*/ */
class MessageManager extends CachedManager { class MessageManager extends CachedManager {
constructor(channel, iterable) { constructor(channel, iterable) {

View File

@@ -2,8 +2,8 @@
const GuildChannel = require('./GuildChannel'); const GuildChannel = require('./GuildChannel');
const TextBasedChannel = require('./interfaces/TextBasedChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel');
const GuildMessageManager = require('../managers/GuildMessageManager');
const GuildTextThreadManager = require('../managers/GuildTextThreadManager'); const GuildTextThreadManager = require('../managers/GuildTextThreadManager');
const MessageManager = require('../managers/MessageManager');
/** /**
* Represents a text-based guild channel on Discord. * Represents a text-based guild channel on Discord.
@@ -16,9 +16,9 @@ class BaseGuildTextChannel extends GuildChannel {
/** /**
* A manager of the messages sent to this channel * A manager of the messages sent to this channel
* @type {MessageManager} * @type {GuildMessageManager}
*/ */
this.messages = new MessageManager(this); this.messages = new GuildMessageManager(this);
/** /**
* A manager of the threads belonging to this channel * A manager of the threads belonging to this channel

View File

@@ -4,7 +4,7 @@ const { Collection } = require('@discordjs/collection');
const { PermissionFlagsBits } = require('discord-api-types/v10'); const { PermissionFlagsBits } = require('discord-api-types/v10');
const GuildChannel = require('./GuildChannel'); const GuildChannel = require('./GuildChannel');
const TextBasedChannel = require('./interfaces/TextBasedChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel');
const MessageManager = require('../managers/MessageManager'); const GuildMessageManager = require('../managers/GuildMessageManager');
/** /**
* Represents a voice-based guild channel on Discord. * Represents a voice-based guild channel on Discord.
@@ -16,9 +16,9 @@ class BaseGuildVoiceChannel extends GuildChannel {
super(guild, data, client, false); super(guild, data, client, false);
/** /**
* A manager of the messages sent to this channel * A manager of the messages sent to this channel
* @type {MessageManager} * @type {GuildMessageManager}
*/ */
this.messages = new MessageManager(this); this.messages = new GuildMessageManager(this);
/** /**
* If the guild considers this channel NSFW * If the guild considers this channel NSFW

View File

@@ -4,7 +4,7 @@ const { userMention } = require('@discordjs/builders');
const { ChannelType } = require('discord-api-types/v10'); const { ChannelType } = require('discord-api-types/v10');
const { BaseChannel } = require('./BaseChannel'); const { BaseChannel } = require('./BaseChannel');
const TextBasedChannel = require('./interfaces/TextBasedChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel');
const MessageManager = require('../managers/MessageManager'); const DMMessageManager = require('../managers/DMMessageManager');
const Partials = require('../util/Partials'); const Partials = require('../util/Partials');
/** /**
@@ -21,9 +21,9 @@ class DMChannel extends BaseChannel {
/** /**
* A manager of the messages belonging to this channel * A manager of the messages belonging to this channel
* @type {MessageManager} * @type {DMMessageManager}
*/ */
this.messages = new MessageManager(this); this.messages = new DMMessageManager(this);
} }
_patch(data) { _patch(data) {

View File

@@ -4,7 +4,7 @@ const { ChannelType, PermissionFlagsBits, Routes, ChannelFlags } = require('disc
const { BaseChannel } = require('./BaseChannel'); const { BaseChannel } = require('./BaseChannel');
const TextBasedChannel = require('./interfaces/TextBasedChannel'); const TextBasedChannel = require('./interfaces/TextBasedChannel');
const { DiscordjsRangeError, ErrorCodes } = require('../errors'); const { DiscordjsRangeError, ErrorCodes } = require('../errors');
const MessageManager = require('../managers/MessageManager'); const GuildMessageManager = require('../managers/GuildMessageManager');
const ThreadMemberManager = require('../managers/ThreadMemberManager'); const ThreadMemberManager = require('../managers/ThreadMemberManager');
const ChannelFlagsBitField = require('../util/ChannelFlagsBitField'); const ChannelFlagsBitField = require('../util/ChannelFlagsBitField');
@@ -31,9 +31,9 @@ class ThreadChannel extends BaseChannel {
/** /**
* A manager of the messages sent to this thread * A manager of the messages sent to this thread
* @type {MessageManager} * @type {GuildMessageManager}
*/ */
this.messages = new MessageManager(this); this.messages = new GuildMessageManager(this);
/** /**
* A manager of the members that are part of this thread * A manager of the members that are part of this thread

View File

@@ -17,9 +17,9 @@ class TextBasedChannel {
constructor() { constructor() {
/** /**
* A manager of the messages sent to this channel * A manager of the messages sent to this channel
* @type {MessageManager} * @type {GuildMessageManager}
*/ */
this.messages = new MessageManager(this); this.messages = new GuildMessageManager(this);
/** /**
* The channel's last message id, if one was sent * The channel's last message id, if one was sent
@@ -410,4 +410,4 @@ module.exports = TextBasedChannel;
// Fixes Circular // Fixes Circular
// eslint-disable-next-line import/order // eslint-disable-next-line import/order
const MessageManager = require('../../managers/MessageManager'); const GuildMessageManager = require('../../managers/GuildMessageManager');

View File

@@ -4005,14 +4005,13 @@ export class GuildMemberRoleManager extends DataManager<Snowflake, Role, RoleRes
): Promise<GuildMember>; ): Promise<GuildMember>;
} }
export class MessageManager<InGuild extends boolean = boolean> extends CachedManager< export abstract class MessageManager<InGuild extends boolean = boolean> extends CachedManager<
Snowflake, Snowflake,
Message<InGuild>, Message<InGuild>,
MessageResolvable MessageResolvable
> { > {
private constructor(channel: TextBasedChannel, iterable?: Iterable<RawMessageData>); protected constructor(channel: TextBasedChannel, iterable?: Iterable<RawMessageData>);
public channel: If<InGuild, GuildTextBasedChannel, TextBasedChannel>; public channel: TextBasedChannel;
public crosspost(message: MessageResolvable): Promise<Message<InGuild>>;
public delete(message: MessageResolvable): Promise<void>; public delete(message: MessageResolvable): Promise<void>;
public edit( public edit(
message: MessageResolvable, message: MessageResolvable,
@@ -4026,6 +4025,15 @@ export class MessageManager<InGuild extends boolean = boolean> extends CachedMan
public unpin(message: MessageResolvable, reason?: string): Promise<void>; public unpin(message: MessageResolvable, reason?: string): Promise<void>;
} }
export class DMMessageManager extends MessageManager {
public channel: DMChannel;
}
export class GuildMessageManager extends MessageManager<true> {
public channel: GuildTextBasedChannel;
public crosspost(message: MessageResolvable): Promise<Message<true>>;
}
export class PermissionOverwriteManager extends CachedManager< export class PermissionOverwriteManager extends CachedManager<
Snowflake, Snowflake,
PermissionOverwrites, PermissionOverwrites,
@@ -4192,7 +4200,7 @@ export interface TextBasedChannelFields<InGuild extends boolean = boolean>
get lastMessage(): Message | null; get lastMessage(): Message | null;
lastPinTimestamp: number | null; lastPinTimestamp: number | null;
get lastPinAt(): Date | null; get lastPinAt(): Date | null;
messages: MessageManager<InGuild>; messages: If<InGuild, GuildMessageManager, DMMessageManager>;
awaitMessageComponent<T extends MessageComponentType>( awaitMessageComponent<T extends MessageComponentType>(
options?: AwaitMessageCollectorOptionsParams<T, true>, options?: AwaitMessageCollectorOptionsParams<T, true>,
): Promise<MappedInteractionTypes[T]>; ): Promise<MappedInteractionTypes[T]>;

View File

@@ -163,6 +163,8 @@ import {
ThreadManager, ThreadManager,
FetchedThreads, FetchedThreads,
FetchedThreadsMore, FetchedThreadsMore,
DMMessageManager,
GuildMessageManager,
ApplicationCommandChannelOptionData, ApplicationCommandChannelOptionData,
ApplicationCommandChannelOption, ApplicationCommandChannelOption,
ApplicationCommandChoicesOption, ApplicationCommandChoicesOption,
@@ -349,6 +351,19 @@ declare const assertIsMessage: (m: Promise<Message>) => void;
client.on('messageCreate', async message => { client.on('messageCreate', async message => {
const { client, channel } = message; const { client, channel } = message;
// https://github.com/discordjs/discord.js/issues/8545
{
// These should not throw any errors when comparing messages from any source.
channel.messages.cache.filter(m => m);
(await channel.messages.fetch()).filter(m => m.author.id === message.author.id);
if (channel.isDMBased()) {
expectType<DMMessageManager>(channel.messages.channel.messages);
} else {
expectType<GuildMessageManager>(channel.messages.channel.messages);
}
}
if (!message.inGuild() && message.partial) { if (!message.inGuild() && message.partial) {
expectNotType<never>(message); expectNotType<never>(message);
} }
@@ -1519,7 +1534,7 @@ declare const guildChannelManager: GuildChannelManager;
if (channel.isTextBased()) { if (channel.isTextBased()) {
const { messages } = channel; const { messages } = channel;
const message = await messages.fetch('123'); const message = await messages.fetch('123');
expectType<MessageManager<true>>(messages); expectType<GuildMessageManager>(messages);
expectType<Promise<Message<true>>>(messages.crosspost('1234567890')); expectType<Promise<Message<true>>>(messages.crosspost('1234567890'));
expectType<Promise<Message<true>>>(messages.edit('1234567890', 'text')); expectType<Promise<Message<true>>>(messages.edit('1234567890', 'text'));
expectType<Promise<Message<true>>>(messages.fetch('1234567890')); expectType<Promise<Message<true>>>(messages.fetch('1234567890'));
@@ -1533,18 +1548,24 @@ declare const guildChannelManager: GuildChannelManager;
{ {
const { messages } = dmChannel; const { messages } = dmChannel;
const message = await messages.fetch('123'); const message = await messages.fetch('123');
expectType<MessageManager<false>>(messages); expectType<DMMessageManager>(messages);
expectType<Promise<Message<false>>>(messages.crosspost('1234567890')); // This shouldn't even exist! expectType<Promise<Message>>(messages.edit('1234567890', 'text'));
expectType<Promise<Message<false>>>(messages.edit('1234567890', 'text')); expectType<Promise<Message>>(messages.fetch('1234567890'));
expectType<Promise<Message<false>>>(messages.fetch('1234567890')); expectType<Promise<Collection<Snowflake, Message>>>(messages.fetchPinned());
expectType<Promise<Collection<Snowflake, Message<false>>>>(messages.fetchPinned()); expectType<Guild | null>(message.guild);
expectType<null>(message.guild); expectType<Snowflake | null>(message.guildId);
expectType<null>(message.guildId); expectType<DMChannel | GuildTextBasedChannel>(message.channel.messages.channel);
expectType<TextBasedChannel>(message.channel.messages.channel); expectType<MessageMentions>(message.mentions);
expectType<Guild | null>(message.mentions.guild);
expectType<Collection<Snowflake, GuildMember> | null>(message.mentions.members);
expectType<MessageMentions<false>>(message.mentions); if (messages.channel.isDMBased()) {
expectType<null>(message.mentions.guild); expectType<DMChannel>(messages.channel);
expectType<null>(message.mentions.members); expectType<DMChannel>(messages.channel.messages.channel);
}
// @ts-expect-error Crossposting is not possible in direct messages.
messages.crosspost('1234567890');
} }
declare const threadManager: ThreadManager; declare const threadManager: ThreadManager;