types: Inference of guild in MessageManager (#8538)

* types: better inference of message manager

* types: alter helper methods

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Jiralite
2022-08-22 09:31:02 +01:00
committed by GitHub
parent 27bbc8fe68
commit 6bb1474d20
2 changed files with 96 additions and 44 deletions

View File

@@ -123,6 +123,7 @@ import {
FormattingPatterns,
APIEmbedProvider,
AuditLogOptionsType,
TextChannelType,
} from 'discord-api-types/v10';
import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events';
@@ -521,7 +522,7 @@ export class BaseGuildEmoji extends Emoji {
public requiresColons: boolean | null;
}
export class BaseGuildTextChannel extends TextBasedChannelMixin(GuildChannel) {
export class BaseGuildTextChannel extends TextBasedChannelMixin(GuildChannel, true) {
protected constructor(guild: Guild, data?: RawGuildChannelData, client?: Client, immediatePatch?: boolean);
public defaultAutoArchiveDuration?: ThreadAutoArchiveDuration;
public rateLimitPerUser: number | null;
@@ -1049,7 +1050,7 @@ export class DataResolver extends null {
public static resolveGuildTemplateCode(data: GuildTemplateResolvable): string;
}
export class DMChannel extends TextBasedChannelMixin(BaseChannel, [
export class DMChannel extends TextBasedChannelMixin(BaseChannel, false, [
'bulkDelete',
'fetchWebhooks',
'createWebhook',
@@ -1675,8 +1676,8 @@ export interface MappedInteractionTypes<Cached extends boolean = boolean> {
[ComponentType.SelectMenu]: SelectMenuInteraction<WrapBooleanCache<Cached>>;
}
export class Message<Cached extends boolean = boolean> extends Base {
private readonly _cacheType: Cached;
export class Message<InGuild extends boolean = boolean> extends Base {
private readonly _cacheType: InGuild;
private constructor(client: Client, data: RawMessageData);
private _patch(data: RawPartialMessageData | RawMessageData): void;
@@ -1684,7 +1685,7 @@ export class Message<Cached extends boolean = boolean> extends Base {
public applicationId: Snowflake | null;
public attachments: Collection<Snowflake, Attachment>;
public author: User;
public get channel(): If<Cached, GuildTextBasedChannel, TextBasedChannel>;
public get channel(): If<InGuild, GuildTextBasedChannel, TextBasedChannel>;
public channelId: Snowflake;
public get cleanContent(): string;
public components: ActionRow<MessageActionRowComponent>[];
@@ -1698,8 +1699,8 @@ export class Message<Cached extends boolean = boolean> extends Base {
public editedTimestamp: number | null;
public embeds: Embed[];
public groupActivityApplication: ClientApplication | null;
public guildId: If<Cached, Snowflake>;
public get guild(): If<Cached, Guild>;
public guildId: If<InGuild, Snowflake>;
public get guild(): If<InGuild, Guild>;
public get hasThread(): boolean;
public id: Snowflake;
public interaction: MessageInteraction | null;
@@ -1720,30 +1721,30 @@ export class Message<Cached extends boolean = boolean> extends Base {
public flags: Readonly<MessageFlagsBitField>;
public reference: MessageReference | null;
public awaitMessageComponent<T extends MessageComponentType>(
options?: AwaitMessageCollectorOptionsParams<T, Cached>,
): Promise<MappedInteractionTypes<Cached>[T]>;
options?: AwaitMessageCollectorOptionsParams<T, InGuild>,
): Promise<MappedInteractionTypes<InGuild>[T]>;
public awaitReactions(options?: AwaitReactionsOptions): Promise<Collection<Snowflake | string, MessageReaction>>;
public createReactionCollector(options?: ReactionCollectorOptions): ReactionCollector;
public createMessageComponentCollector<T extends MessageComponentType>(
options?: MessageCollectorOptionsParams<T, Cached>,
): InteractionCollector<MappedInteractionTypes<Cached>[T]>;
public delete(): Promise<Message>;
public edit(content: string | MessageEditOptions | MessagePayload): Promise<Message>;
options?: MessageCollectorOptionsParams<T, InGuild>,
): InteractionCollector<MappedInteractionTypes<InGuild>[T]>;
public delete(): Promise<Message<InGuild>>;
public edit(content: string | MessageEditOptions | MessagePayload): Promise<Message<InGuild>>;
public equals(message: Message, rawData: unknown): boolean;
public fetchReference(): Promise<Message>;
public fetchReference(): Promise<Message<InGuild>>;
public fetchWebhook(): Promise<Webhook>;
public crosspost(): Promise<Message>;
public fetch(force?: boolean): Promise<Message>;
public pin(reason?: string): Promise<Message>;
public crosspost(): Promise<Message<InGuild>>;
public fetch(force?: boolean): Promise<Message<InGuild>>;
public pin(reason?: string): Promise<Message<InGuild>>;
public react(emoji: EmojiIdentifierResolvable): Promise<MessageReaction>;
public removeAttachments(): Promise<Message>;
public reply(options: string | MessagePayload | ReplyMessageOptions): Promise<Message>;
public removeAttachments(): Promise<Message<InGuild>>;
public reply(options: string | MessagePayload | ReplyMessageOptions): Promise<Message<InGuild>>;
public resolveComponent(customId: string): MessageActionRowComponent | null;
public startThread(options: StartThreadOptions): Promise<AnyThreadChannel>;
public suppressEmbeds(suppress?: boolean): Promise<Message>;
public suppressEmbeds(suppress?: boolean): Promise<Message<InGuild>>;
public toJSON(): unknown;
public toString(): string;
public unpin(reason?: string): Promise<Message>;
public unpin(reason?: string): Promise<Message<InGuild>>;
public inGuild(): this is Message<true> & this;
}
@@ -2506,7 +2507,11 @@ export interface PrivateThreadChannel extends ThreadChannel {
type: ChannelType.GuildPrivateThread;
}
export class ThreadChannel extends TextBasedChannelMixin(BaseChannel, ['fetchWebhooks', 'createWebhook', 'setNSFW']) {
export class ThreadChannel extends TextBasedChannelMixin(BaseChannel, true, [
'fetchWebhooks',
'createWebhook',
'setNSFW',
]) {
private constructor(guild: Guild, data?: RawThreadChannelData, client?: Client, fromInteraction?: boolean);
public archived: boolean | null;
public get archivedAt(): Date | null;
@@ -2752,7 +2757,10 @@ export type ComponentData =
| ModalActionRowComponentData
| ActionRowData<MessageActionRowComponentData | ModalActionRowComponentData>;
export class VoiceChannel extends TextBasedChannelMixin(BaseGuildVoiceChannel, ['lastPinTimestamp', 'lastPinAt']) {
export class VoiceChannel extends TextBasedChannelMixin(BaseGuildVoiceChannel, true, [
'lastPinTimestamp',
'lastPinAt',
]) {
public videoQualityMode: VideoQualityMode | null;
public get speakable(): boolean;
public type: ChannelType.GuildVoice;
@@ -3518,15 +3526,22 @@ export class GuildMemberRoleManager extends DataManager<Snowflake, Role, RoleRes
): Promise<GuildMember>;
}
export class MessageManager extends CachedManager<Snowflake, Message, MessageResolvable> {
export class MessageManager<InGuild extends boolean = boolean> extends CachedManager<
Snowflake,
Message<InGuild>,
MessageResolvable
> {
private constructor(channel: TextBasedChannel, iterable?: Iterable<RawMessageData>);
public channel: TextBasedChannel;
public crosspost(message: MessageResolvable): Promise<Message>;
public channel: If<InGuild, GuildTextBasedChannel, TextBasedChannel>;
public crosspost(message: MessageResolvable): Promise<Message<InGuild>>;
public delete(message: MessageResolvable): Promise<void>;
public edit(message: MessageResolvable, options: string | MessagePayload | MessageEditOptions): Promise<Message>;
public fetch(options: MessageResolvable | FetchMessageOptions): Promise<Message>;
public fetch(options?: FetchMessagesOptions): Promise<Collection<Snowflake, Message>>;
public fetchPinned(cache?: boolean): Promise<Collection<Snowflake, Message>>;
public edit(
message: MessageResolvable,
options: string | MessagePayload | MessageEditOptions,
): Promise<Message<InGuild>>;
public fetch(options: MessageResolvable | FetchMessageOptions): Promise<Message<InGuild>>;
public fetch(options?: FetchMessagesOptions): Promise<Collection<Snowflake, Message<InGuild>>>;
public fetchPinned(cache?: boolean): Promise<Collection<Snowflake, Message<InGuild>>>;
public react(message: MessageResolvable, emoji: EmojiIdentifierResolvable): Promise<void>;
public pin(message: MessageResolvable, reason?: string): Promise<void>;
public unpin(message: MessageResolvable, reason?: string): Promise<void>;
@@ -3649,22 +3664,31 @@ export class VoiceStateManager extends CachedManager<Snowflake, VoiceState, type
// to each of those classes
export type Constructable<T> = abstract new (...args: any[]) => T;
export function PartialTextBasedChannel<T>(Base?: Constructable<T>): Constructable<T & PartialTextBasedChannelFields>;
export function TextBasedChannelMixin<T, I extends keyof TextBasedChannelFields = never>(
export function PartialTextBasedChannel<T>(
Base?: Constructable<T>,
ignore?: I[],
): Constructable<T & Omit<TextBasedChannelFields, I>>;
): Constructable<T & PartialTextBasedChannelFields<false>>;
export interface PartialTextBasedChannelFields {
send(options: string | MessagePayload | MessageOptions): Promise<Message>;
export function TextBasedChannelMixin<
T,
InGuild extends boolean = boolean,
I extends keyof TextBasedChannelFields<InGuild> = never,
>(
Base?: Constructable<T>,
inGuild?: InGuild,
ignore?: I[],
): Constructable<T & Omit<TextBasedChannelFields<InGuild>, I>>;
export interface PartialTextBasedChannelFields<InGuild extends boolean = boolean> {
send(options: string | MessagePayload | MessageOptions): Promise<Message<InGuild>>;
}
export interface TextBasedChannelFields extends PartialTextBasedChannelFields {
export interface TextBasedChannelFields<InGuild extends boolean = boolean>
extends PartialTextBasedChannelFields<InGuild> {
lastMessageId: Snowflake | null;
get lastMessage(): Message | null;
lastPinTimestamp: number | null;
get lastPinAt(): Date | null;
messages: MessageManager;
messages: MessageManager<InGuild>;
awaitMessageComponent<T extends MessageComponentType>(
options?: AwaitMessageCollectorOptionsParams<T, true>,
): Promise<MappedInteractionTypes[T]>;
@@ -5521,7 +5545,7 @@ export type Channel =
| AnyThreadChannel
| VoiceChannel;
export type TextBasedChannel = Extract<Channel, { messages: MessageManager }>;
export type TextBasedChannel = Exclude<Extract<Channel, { type: TextChannelType }>, PartialGroupDMChannel>;
export type TextBasedChannelTypes = TextBasedChannel['type'];

View File

@@ -1049,11 +1049,11 @@ declare const user: User;
declare const guildMember: GuildMember;
// Test whether the structures implement send
expectType<TextBasedChannelFields['send']>(dmChannel.send);
expectType<TextBasedChannelFields['send']>(threadChannel.send);
expectType<TextBasedChannelFields['send']>(newsChannel.send);
expectType<TextBasedChannelFields['send']>(textChannel.send);
expectType<TextBasedChannelFields['send']>(voiceChannel.send);
expectType<TextBasedChannelFields<false>['send']>(dmChannel.send);
expectType<TextBasedChannelFields<true>['send']>(threadChannel.send);
expectType<TextBasedChannelFields<true>['send']>(newsChannel.send);
expectType<TextBasedChannelFields<true>['send']>(textChannel.send);
expectType<TextBasedChannelFields<true>['send']>(voiceChannel.send);
expectAssignable<PartialTextBasedChannelFields>(user);
expectAssignable<PartialTextBasedChannelFields>(guildMember);
@@ -1190,6 +1190,34 @@ declare const guildChannelManager: GuildChannelManager;
expectType<Promise<Collection<Snowflake, AnyChannel>>>(guildChannelManager.fetch());
expectType<Promise<Collection<Snowflake, AnyChannel>>>(guildChannelManager.fetch(undefined, {}));
expectType<Promise<AnyChannel | null>>(guildChannelManager.fetch('0'));
const channel = guildChannelManager.cache.first()!;
if (channel.isTextBased()) {
const { messages } = channel;
const message = await messages.fetch('123');
expectType<MessageManager<true>>(messages);
expectType<Promise<Message<true>>>(messages.crosspost('1234567890'));
expectType<Promise<Message<true>>>(messages.edit('1234567890', 'text'));
expectType<Promise<Message<true>>>(messages.fetch('1234567890'));
expectType<Promise<Collection<Snowflake, Message<true>>>>(messages.fetchPinned());
expectType<Guild>(message.guild);
expectType<Snowflake>(message.guildId);
expectType<GuildTextBasedChannel>(message.channel.messages.channel);
}
}
{
const { messages } = dmChannel;
const message = await messages.fetch('123');
expectType<MessageManager<false>>(messages);
expectType<Promise<Message<false>>>(messages.crosspost('1234567890')); // This shouldn't even exist!
expectType<Promise<Message<false>>>(messages.edit('1234567890', 'text'));
expectType<Promise<Message<false>>>(messages.fetch('1234567890'));
expectType<Promise<Collection<Snowflake, Message<false>>>>(messages.fetchPinned());
expectType<null>(message.guild);
expectType<null>(message.guildId);
expectType<TextBasedChannel>(message.channel.messages.channel);
}
declare const messageManager: MessageManager;