From 2c1fbda621fc1c1ea227295c578e6d8486dbc4f2 Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Wed, 19 Jan 2022 08:58:02 -0500 Subject: [PATCH] types: Add tagged `type` unions for channel types (#200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: All of the channel types are now split based on their type. As such, you will need to assert the type (either by checking it with the enum or by casting the data as the correct channel) before accessing data. *If you encounter any missing properties due to this, please open an issue! This is a big change, and we hope nothing is missing* Co-authored-by: Vlad Frangu Co-authored-by: Antonio Román --- .gitignore | 3 + deno/payloads/v8/channel.ts | 134 +++++++++++++++++++------- deno/payloads/v9/channel.ts | 182 +++++++++++++++++++++++++++--------- deno/rest/v8/guild.ts | 9 +- deno/rest/v9/guild.ts | 9 +- deno/utils/internals.ts | 2 + payloads/v8/channel.ts | 134 +++++++++++++++++++------- payloads/v9/channel.ts | 182 +++++++++++++++++++++++++++--------- rest/v8/guild.ts | 9 +- rest/v9/guild.ts | 9 +- utils/internals.ts | 2 + 11 files changed, 511 insertions(+), 164 deletions(-) diff --git a/.gitignore b/.gitignore index 61aa2ebc3..cc966e894 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ voice/**/*.js voice/**/*.map voice/**/*.d.ts voice/**/*.mjs + +# macOS files +.DS_store diff --git a/deno/payloads/v8/channel.ts b/deno/payloads/v8/channel.ts index 23bcf6fae..621c15107 100644 --- a/deno/payloads/v8/channel.ts +++ b/deno/payloads/v8/channel.ts @@ -32,17 +32,37 @@ export interface APIPartialChannel { } /** - * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + * This interface is used to allow easy extension for other channel types. While + * also allowing `APIPartialChannel` to be used without breaking. */ -export interface APIChannel extends APIPartialChannel { +export interface APIChannelBase extends APIPartialChannel { + type: T; +} + +// TODO: update when text in voice is released +export type TextChannelType = ChannelType.DM | ChannelType.GroupDM | ChannelType.GuildNews | ChannelType.GuildText; + +export type GuildChannelType = Exclude< + | TextChannelType + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ChannelType.GuildNews + | ChannelType.GuildStore, + ChannelType.DM | ChannelType.GroupDM +>; + +export interface APITextBasedChannel extends APIChannelBase { /** - * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) + * The id of the last message sent in this channel (may not point to an existing or valid message) */ - guild_id?: Snowflake; + last_message_id?: Snowflake | null; +} + +export interface APIGuildChannel extends APIChannelBase { /** - * Sorting position of the channel + * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) */ - position?: number; + guild_id?: Snowflake; /** * Explicit permission overwrites for members and roles * @@ -50,17 +70,48 @@ export interface APIChannel extends APIPartialChannel { */ permission_overwrites?: APIOverwrite[]; /** - * The channel topic (0-1024 characters) + * Sorting position of the channel */ - topic?: string | null; + position?: number; + /** + * ID of the parent category for a channel (each parent category can contain up to 50 channels) + */ + parent_id?: Snowflake | null; /** * Whether the channel is nsfw */ nsfw?: boolean; +} + +export type GuildTextChannelType = Exclude; + +export interface APIGuildTextChannel + extends APITextBasedChannel, + APIGuildChannel { /** - * The id of the last message sent in this channel (may not point to an existing or valid message) + * The channel topic (0-1024 characters) */ - last_message_id?: Snowflake | null; + topic?: string | null; + /** + * When the last pinned message was pinned. + * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned + */ + last_pin_timestamp?: string | null; +} + +export interface APITextChannel extends APIGuildTextChannel { + /** + * Amount of seconds a user has to wait before sending another message (0-21600); + * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + */ + rate_limit_per_user?: number; +} + +export type APINewsChannel = APIGuildTextChannel; +export type APIGuildCategoryChannel = APIGuildChannel; +export type APIGuildStoreChannel = APIGuildChannel; + +export interface APIVoiceChannel extends APIGuildChannel { /** * The bitrate (in bits) of the voice channel */ @@ -70,51 +121,62 @@ export interface APIChannel extends APIPartialChannel { */ user_limit?: number; /** - * Amount of seconds a user has to wait before sending another message (0-21600); - * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + * Voice region id for the voice or stage channel, automatic when set to `null` + * + * See https://discord.com/developers/docs/resources/voice#voice-region-object */ - rate_limit_per_user?: number; + rtc_region?: string | null; + /** + * The camera video quality mode of the voice channel, `1` when not present + * + * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes + */ + video_quality_mode?: VideoQualityMode; +} + +interface APIDMChannelBase extends APITextBasedChannel { /** * The recipients of the DM * * See https://discord.com/developers/docs/resources/user#user-object */ recipients?: APIUser[]; - /** - * Icon hash - */ - icon?: string | null; - /** - * ID of the DM creator - */ - owner_id?: Snowflake; +} + +export type APIDMChannel = APIDMChannelBase; + +export interface APIGroupDMChannel extends APIDMChannelBase { /** * Application id of the group DM creator if it is bot-created */ application_id?: Snowflake; /** - * ID of the parent category for a channel (each parent category can contain up to 50 channels) - */ - parent_id?: Snowflake | null; - /** - * When the last pinned message was pinned. - * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned + * Icon hash */ - last_pin_timestamp?: string | null; + icon?: string | null; /** - * Voice region id for the voice or stage channel, automatic when set to `null` - * - * See https://discord.com/developers/docs/resources/voice#voice-region-object + * ID of the DM creator */ - rtc_region?: string | null; + owner_id?: Snowflake; /** - * The camera video quality mode of the voice channel, `1` when not present - * - * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes + * The id of the last message sent in this channel (may not point to an existing or valid message) */ - video_quality_mode?: VideoQualityMode; + last_message_id?: Snowflake | null; } +/** + * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + */ +export type APIChannel = + | APIGroupDMChannel + | APIDMChannel + | APITextChannel + | APINewsChannel + | APIGuildStoreChannel + | APIVoiceChannel + | APIGuildCategoryChannel + | APINewsChannel; + /** * https://discord.com/developers/docs/resources/channel#channel-object-channel-types */ diff --git a/deno/payloads/v9/channel.ts b/deno/payloads/v9/channel.ts index 548d60a96..24f35480c 100644 --- a/deno/payloads/v9/channel.ts +++ b/deno/payloads/v9/channel.ts @@ -32,17 +32,44 @@ export interface APIPartialChannel { } /** - * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + * This interface is used to allow easy extension for other channel types. While + * also allowing `APIPartialChannel` to be used without breaking. */ -export interface APIChannel extends APIPartialChannel { +export interface APIChannelBase extends APIPartialChannel { + type: T; +} + +// TODO: update when text in voice is released +export type TextChannelType = + | ChannelType.DM + | ChannelType.GroupDM + | ChannelType.GuildNews + | ChannelType.GuildPublicThread + | ChannelType.GuildPrivateThread + | ChannelType.GuildNewsThread + | ChannelType.GuildText; + +export type GuildChannelType = Exclude< + | TextChannelType + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ChannelType.GuildNews + | ChannelType.GuildStore, + ChannelType.DM | ChannelType.GroupDM +>; + +export interface APITextBasedChannel extends APIChannelBase { /** - * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) + * The id of the last message sent in this channel (may not point to an existing or valid message) */ - guild_id?: Snowflake; + last_message_id?: Snowflake | null; +} + +export interface APIGuildChannel extends APIChannelBase { /** - * Sorting position of the channel + * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) */ - position?: number; + guild_id?: Snowflake; /** * Explicit permission overwrites for members and roles * @@ -50,25 +77,44 @@ export interface APIChannel extends APIPartialChannel { */ permission_overwrites?: APIOverwrite[]; /** - * The channel topic (0-1024 characters) + * Sorting position of the channel */ - topic?: string | null; + position?: number; + /** + * ID of the parent category for a channel (each parent category can contain up to 50 channels) + * + * OR + * + * ID of the parent channel for a thread + */ + parent_id?: Snowflake | null; /** * Whether the channel is nsfw */ nsfw?: boolean; +} + +export type GuildTextChannelType = Exclude; + +export interface APIGuildTextChannel + extends APITextBasedChannel, + APIGuildChannel { /** - * The id of the last message sent in this channel (may not point to an existing or valid message) + * Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity */ - last_message_id?: Snowflake | null; + default_auto_archive_duration?: ThreadAutoArchiveDuration; /** - * The bitrate (in bits) of the voice channel + * The channel topic (0-1024 characters) */ - bitrate?: number; + topic?: string | null; /** - * The user limit of the voice channel + * When the last pinned message was pinned. + * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned */ - user_limit?: number; + last_pin_timestamp?: string | null; +} + +export interface APITextChannel extends APIGuildTextChannel { /** * Amount of seconds a user has to wait before sending another message (0-21600); * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected @@ -79,49 +125,77 @@ export interface APIChannel extends APIPartialChannel { * The absence of this field in API calls and Gateway events should indicate that slowmode has been reset to the default value. */ rate_limit_per_user?: number; +} + +export type APINewsChannel = APIGuildTextChannel; +export type APIGuildCategoryChannel = APIGuildChannel; +export type APIGuildStoreChannel = APIGuildChannel; + +export interface APIVoiceChannel extends APIGuildChannel { /** - * The recipients of the DM + * The bitrate (in bits) of the voice channel + */ + bitrate?: number; + /** + * The user limit of the voice channel + */ + user_limit?: number; + /** + * Voice region id for the voice or stage channel, automatic when set to `null` * - * See https://discord.com/developers/docs/resources/user#user-object + * See https://discord.com/developers/docs/resources/voice#voice-region-object */ - recipients?: APIUser[]; + rtc_region?: string | null; /** - * Icon hash + * The camera video quality mode of the voice channel, `1` when not present + * + * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes */ - icon?: string | null; + video_quality_mode?: VideoQualityMode; +} + +interface APIDMChannelBase extends APITextBasedChannel { /** - * ID of the DM creator or thread creator + * The recipients of the DM + * + * See https://discord.com/developers/docs/resources/user#user-object */ - owner_id?: Snowflake; + recipients?: APIUser[]; +} + +export type APIDMChannel = APIDMChannelBase; + +export interface APIGroupDMChannel extends APIDMChannelBase { /** * Application id of the group DM creator if it is bot-created */ application_id?: Snowflake; /** - * ID of the parent category for a channel (each parent category can contain up to 50 channels) - * - * OR - * - * ID of the parent channel for a thread + * Icon hash */ - parent_id?: Snowflake | null; + icon?: string | null; /** - * When the last pinned message was pinned. - * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned + * ID of the DM creator */ - last_pin_timestamp?: string | null; + owner_id?: Snowflake; /** - * Voice region id for the voice or stage channel, automatic when set to `null` - * - * See https://discord.com/developers/docs/resources/voice#voice-region-object + * The id of the last message sent in this channel (may not point to an existing or valid message) */ - rtc_region?: string | null; + last_message_id?: Snowflake | null; +} + +export interface APIThreadChannel + extends APIGuildChannel< + ChannelType.GuildPublicThread | ChannelType.GuildPrivateThread | ChannelType.GuildNewsThread + > { /** - * The camera video quality mode of the voice channel, `1` when not present - * - * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes + * The client users member for the thread, only included in select endpoints */ - video_quality_mode?: VideoQualityMode; + member?: APIThreadMember; + /** + * The metadata for a thread channel not shared by other channels + */ + thread_metadata?: APIThreadMetadata; /** * The approximate message count of the thread, does not count above 50 even if there are more messages */ @@ -131,19 +205,39 @@ export interface APIChannel extends APIPartialChannel { */ member_count?: number; /** - * The metadata for a thread channel not shared by other channels + * Amount of seconds a user has to wait before sending another message (0-21600); + * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + * + * `rate_limit_per_user` also applies to thread creation. Users can send one message and create one thread during each `rate_limit_per_user` interval. + * + * For thread channels, `rate_limit_per_user` is only returned if the field is set to a non-zero and non-null value. + * The absence of this field in API calls and Gateway events should indicate that slowmode has been reset to the default value. */ - thread_metadata?: APIThreadMetadata; + rate_limit_per_user?: number; /** - * The client users member for the thread, only included in select endpoints + * ID of the thread creator */ - member?: APIThreadMember; + owner_id?: Snowflake; /** - * Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity + * The id of the last message sent in this thread (may not point to an existing or valid message) */ - default_auto_archive_duration?: ThreadAutoArchiveDuration; + last_message_id?: Snowflake | null; } +/** + * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + */ +export type APIChannel = + | APIGroupDMChannel + | APIDMChannel + | APITextChannel + | APINewsChannel + | APIGuildStoreChannel + | APIVoiceChannel + | APIGuildCategoryChannel + | APIThreadChannel + | APINewsChannel; + /** * https://discord.com/developers/docs/resources/channel#channel-object-channel-types */ diff --git a/deno/rest/v8/guild.ts b/deno/rest/v8/guild.ts index 83d577f86..abbd86255 100644 --- a/deno/rest/v8/guild.ts +++ b/deno/rest/v8/guild.ts @@ -2,7 +2,9 @@ import type { Permissions, Snowflake } from '../../globals.ts'; import type { APIBan, APIChannel, + APIDMChannel, APIExtendedInvite, + APIGroupDMChannel, APIGuild, APIGuildIntegration, APIGuildMember, @@ -25,6 +27,7 @@ import type { Nullable, StrictPartial, StrictRequired, + UnionToIntersection, } from '../../utils/internals.ts'; import type { RESTPutAPIChannelPermissionJSONBody } from './channel.ts'; @@ -32,8 +35,12 @@ export interface APIGuildCreateOverwrite extends RESTPutAPIChannelPermissionJSON id: number | string; } +export type APIGuildChannelResolvable = Exclude; export type APIGuildCreatePartialChannel = StrictPartial< - Pick + Pick< + UnionToIntersection, + 'type' | 'topic' | 'nsfw' | 'bitrate' | 'user_limit' | 'rate_limit_per_user' + > > & AddUndefinedToPossiblyUndefinedPropertiesOfInterface<{ name: string; diff --git a/deno/rest/v9/guild.ts b/deno/rest/v9/guild.ts index 81645aea9..79b6a3e04 100644 --- a/deno/rest/v9/guild.ts +++ b/deno/rest/v9/guild.ts @@ -20,12 +20,15 @@ import type { GuildSystemChannelFlags, GuildVerificationLevel, GuildWidgetStyle, + APIDMChannel, + APIGroupDMChannel, } from '../../payloads/v9/mod.ts'; import type { AddUndefinedToPossiblyUndefinedPropertiesOfInterface, Nullable, StrictPartial, StrictRequired, + UnionToIntersection, } from '../../utils/internals.ts'; import type { RESTPutAPIChannelPermissionJSONBody } from './channel.ts'; @@ -33,8 +36,12 @@ export interface APIGuildCreateOverwrite extends RESTPutAPIChannelPermissionJSON id: number | string; } +export type APIGuildChannelResolvable = Exclude; export type APIGuildCreatePartialChannel = StrictPartial< - Pick + Pick< + UnionToIntersection, + 'type' | 'topic' | 'nsfw' | 'bitrate' | 'user_limit' | 'rate_limit_per_user' + > > & AddUndefinedToPossiblyUndefinedPropertiesOfInterface<{ name: string; diff --git a/deno/utils/internals.ts b/deno/utils/internals.ts index 305ded2e8..fea21fab8 100644 --- a/deno/utils/internals.ts +++ b/deno/utils/internals.ts @@ -13,3 +13,5 @@ export type AddUndefinedToPossiblyUndefinedPropertiesOfInterface = { export type StrictPartial = AddUndefinedToPossiblyUndefinedPropertiesOfInterface>; export type StrictRequired = Required<{ [K in keyof Base]: Exclude }>; + +export type UnionToIntersection = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never; diff --git a/payloads/v8/channel.ts b/payloads/v8/channel.ts index afda486dd..7aab50f85 100644 --- a/payloads/v8/channel.ts +++ b/payloads/v8/channel.ts @@ -32,17 +32,37 @@ export interface APIPartialChannel { } /** - * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + * This interface is used to allow easy extension for other channel types. While + * also allowing `APIPartialChannel` to be used without breaking. */ -export interface APIChannel extends APIPartialChannel { +export interface APIChannelBase extends APIPartialChannel { + type: T; +} + +// TODO: update when text in voice is released +export type TextChannelType = ChannelType.DM | ChannelType.GroupDM | ChannelType.GuildNews | ChannelType.GuildText; + +export type GuildChannelType = Exclude< + | TextChannelType + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ChannelType.GuildNews + | ChannelType.GuildStore, + ChannelType.DM | ChannelType.GroupDM +>; + +export interface APITextBasedChannel extends APIChannelBase { /** - * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) + * The id of the last message sent in this channel (may not point to an existing or valid message) */ - guild_id?: Snowflake; + last_message_id?: Snowflake | null; +} + +export interface APIGuildChannel extends APIChannelBase { /** - * Sorting position of the channel + * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) */ - position?: number; + guild_id?: Snowflake; /** * Explicit permission overwrites for members and roles * @@ -50,17 +70,48 @@ export interface APIChannel extends APIPartialChannel { */ permission_overwrites?: APIOverwrite[]; /** - * The channel topic (0-1024 characters) + * Sorting position of the channel */ - topic?: string | null; + position?: number; + /** + * ID of the parent category for a channel (each parent category can contain up to 50 channels) + */ + parent_id?: Snowflake | null; /** * Whether the channel is nsfw */ nsfw?: boolean; +} + +export type GuildTextChannelType = Exclude; + +export interface APIGuildTextChannel + extends APITextBasedChannel, + APIGuildChannel { /** - * The id of the last message sent in this channel (may not point to an existing or valid message) + * The channel topic (0-1024 characters) */ - last_message_id?: Snowflake | null; + topic?: string | null; + /** + * When the last pinned message was pinned. + * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned + */ + last_pin_timestamp?: string | null; +} + +export interface APITextChannel extends APIGuildTextChannel { + /** + * Amount of seconds a user has to wait before sending another message (0-21600); + * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + */ + rate_limit_per_user?: number; +} + +export type APINewsChannel = APIGuildTextChannel; +export type APIGuildCategoryChannel = APIGuildChannel; +export type APIGuildStoreChannel = APIGuildChannel; + +export interface APIVoiceChannel extends APIGuildChannel { /** * The bitrate (in bits) of the voice channel */ @@ -70,51 +121,62 @@ export interface APIChannel extends APIPartialChannel { */ user_limit?: number; /** - * Amount of seconds a user has to wait before sending another message (0-21600); - * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + * Voice region id for the voice or stage channel, automatic when set to `null` + * + * See https://discord.com/developers/docs/resources/voice#voice-region-object */ - rate_limit_per_user?: number; + rtc_region?: string | null; + /** + * The camera video quality mode of the voice channel, `1` when not present + * + * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes + */ + video_quality_mode?: VideoQualityMode; +} + +interface APIDMChannelBase extends APITextBasedChannel { /** * The recipients of the DM * * See https://discord.com/developers/docs/resources/user#user-object */ recipients?: APIUser[]; - /** - * Icon hash - */ - icon?: string | null; - /** - * ID of the DM creator - */ - owner_id?: Snowflake; +} + +export type APIDMChannel = APIDMChannelBase; + +export interface APIGroupDMChannel extends APIDMChannelBase { /** * Application id of the group DM creator if it is bot-created */ application_id?: Snowflake; /** - * ID of the parent category for a channel (each parent category can contain up to 50 channels) - */ - parent_id?: Snowflake | null; - /** - * When the last pinned message was pinned. - * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned + * Icon hash */ - last_pin_timestamp?: string | null; + icon?: string | null; /** - * Voice region id for the voice or stage channel, automatic when set to `null` - * - * See https://discord.com/developers/docs/resources/voice#voice-region-object + * ID of the DM creator */ - rtc_region?: string | null; + owner_id?: Snowflake; /** - * The camera video quality mode of the voice channel, `1` when not present - * - * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes + * The id of the last message sent in this channel (may not point to an existing or valid message) */ - video_quality_mode?: VideoQualityMode; + last_message_id?: Snowflake | null; } +/** + * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + */ +export type APIChannel = + | APIGroupDMChannel + | APIDMChannel + | APITextChannel + | APINewsChannel + | APIGuildStoreChannel + | APIVoiceChannel + | APIGuildCategoryChannel + | APINewsChannel; + /** * https://discord.com/developers/docs/resources/channel#channel-object-channel-types */ diff --git a/payloads/v9/channel.ts b/payloads/v9/channel.ts index 5ee9dc2a3..8c1108a67 100644 --- a/payloads/v9/channel.ts +++ b/payloads/v9/channel.ts @@ -32,17 +32,44 @@ export interface APIPartialChannel { } /** - * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + * This interface is used to allow easy extension for other channel types. While + * also allowing `APIPartialChannel` to be used without breaking. */ -export interface APIChannel extends APIPartialChannel { +export interface APIChannelBase extends APIPartialChannel { + type: T; +} + +// TODO: update when text in voice is released +export type TextChannelType = + | ChannelType.DM + | ChannelType.GroupDM + | ChannelType.GuildNews + | ChannelType.GuildPublicThread + | ChannelType.GuildPrivateThread + | ChannelType.GuildNewsThread + | ChannelType.GuildText; + +export type GuildChannelType = Exclude< + | TextChannelType + | ChannelType.GuildVoice + | ChannelType.GuildStageVoice + | ChannelType.GuildNews + | ChannelType.GuildStore, + ChannelType.DM | ChannelType.GroupDM +>; + +export interface APITextBasedChannel extends APIChannelBase { /** - * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) + * The id of the last message sent in this channel (may not point to an existing or valid message) */ - guild_id?: Snowflake; + last_message_id?: Snowflake | null; +} + +export interface APIGuildChannel extends APIChannelBase { /** - * Sorting position of the channel + * The id of the guild (may be missing for some channel objects received over gateway guild dispatches) */ - position?: number; + guild_id?: Snowflake; /** * Explicit permission overwrites for members and roles * @@ -50,25 +77,44 @@ export interface APIChannel extends APIPartialChannel { */ permission_overwrites?: APIOverwrite[]; /** - * The channel topic (0-1024 characters) + * Sorting position of the channel */ - topic?: string | null; + position?: number; + /** + * ID of the parent category for a channel (each parent category can contain up to 50 channels) + * + * OR + * + * ID of the parent channel for a thread + */ + parent_id?: Snowflake | null; /** * Whether the channel is nsfw */ nsfw?: boolean; +} + +export type GuildTextChannelType = Exclude; + +export interface APIGuildTextChannel + extends APITextBasedChannel, + APIGuildChannel { /** - * The id of the last message sent in this channel (may not point to an existing or valid message) + * Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity */ - last_message_id?: Snowflake | null; + default_auto_archive_duration?: ThreadAutoArchiveDuration; /** - * The bitrate (in bits) of the voice channel + * The channel topic (0-1024 characters) */ - bitrate?: number; + topic?: string | null; /** - * The user limit of the voice channel + * When the last pinned message was pinned. + * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned */ - user_limit?: number; + last_pin_timestamp?: string | null; +} + +export interface APITextChannel extends APIGuildTextChannel { /** * Amount of seconds a user has to wait before sending another message (0-21600); * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected @@ -79,49 +125,77 @@ export interface APIChannel extends APIPartialChannel { * The absence of this field in API calls and Gateway events should indicate that slowmode has been reset to the default value. */ rate_limit_per_user?: number; +} + +export type APINewsChannel = APIGuildTextChannel; +export type APIGuildCategoryChannel = APIGuildChannel; +export type APIGuildStoreChannel = APIGuildChannel; + +export interface APIVoiceChannel extends APIGuildChannel { /** - * The recipients of the DM + * The bitrate (in bits) of the voice channel + */ + bitrate?: number; + /** + * The user limit of the voice channel + */ + user_limit?: number; + /** + * Voice region id for the voice or stage channel, automatic when set to `null` * - * See https://discord.com/developers/docs/resources/user#user-object + * See https://discord.com/developers/docs/resources/voice#voice-region-object */ - recipients?: APIUser[]; + rtc_region?: string | null; /** - * Icon hash + * The camera video quality mode of the voice channel, `1` when not present + * + * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes */ - icon?: string | null; + video_quality_mode?: VideoQualityMode; +} + +interface APIDMChannelBase extends APITextBasedChannel { /** - * ID of the DM creator or thread creator + * The recipients of the DM + * + * See https://discord.com/developers/docs/resources/user#user-object */ - owner_id?: Snowflake; + recipients?: APIUser[]; +} + +export type APIDMChannel = APIDMChannelBase; + +export interface APIGroupDMChannel extends APIDMChannelBase { /** * Application id of the group DM creator if it is bot-created */ application_id?: Snowflake; /** - * ID of the parent category for a channel (each parent category can contain up to 50 channels) - * - * OR - * - * ID of the parent channel for a thread + * Icon hash */ - parent_id?: Snowflake | null; + icon?: string | null; /** - * When the last pinned message was pinned. - * This may be `null` in events such as `GUILD_CREATE` when a message is not pinned + * ID of the DM creator */ - last_pin_timestamp?: string | null; + owner_id?: Snowflake; /** - * Voice region id for the voice or stage channel, automatic when set to `null` - * - * See https://discord.com/developers/docs/resources/voice#voice-region-object + * The id of the last message sent in this channel (may not point to an existing or valid message) */ - rtc_region?: string | null; + last_message_id?: Snowflake | null; +} + +export interface APIThreadChannel + extends APIGuildChannel< + ChannelType.GuildPublicThread | ChannelType.GuildPrivateThread | ChannelType.GuildNewsThread + > { /** - * The camera video quality mode of the voice channel, `1` when not present - * - * See https://discord.com/developers/docs/resources/channel#channel-object-video-quality-modes + * The client users member for the thread, only included in select endpoints */ - video_quality_mode?: VideoQualityMode; + member?: APIThreadMember; + /** + * The metadata for a thread channel not shared by other channels + */ + thread_metadata?: APIThreadMetadata; /** * The approximate message count of the thread, does not count above 50 even if there are more messages */ @@ -131,19 +205,39 @@ export interface APIChannel extends APIPartialChannel { */ member_count?: number; /** - * The metadata for a thread channel not shared by other channels + * Amount of seconds a user has to wait before sending another message (0-21600); + * bots, as well as users with the permission `MANAGE_MESSAGES` or `MANAGE_CHANNELS`, are unaffected + * + * `rate_limit_per_user` also applies to thread creation. Users can send one message and create one thread during each `rate_limit_per_user` interval. + * + * For thread channels, `rate_limit_per_user` is only returned if the field is set to a non-zero and non-null value. + * The absence of this field in API calls and Gateway events should indicate that slowmode has been reset to the default value. */ - thread_metadata?: APIThreadMetadata; + rate_limit_per_user?: number; /** - * The client users member for the thread, only included in select endpoints + * ID of the thread creator */ - member?: APIThreadMember; + owner_id?: Snowflake; /** - * Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity + * The id of the last message sent in this thread (may not point to an existing or valid message) */ - default_auto_archive_duration?: ThreadAutoArchiveDuration; + last_message_id?: Snowflake | null; } +/** + * https://discord.com/developers/docs/resources/channel#channel-object-channel-structure + */ +export type APIChannel = + | APIGroupDMChannel + | APIDMChannel + | APITextChannel + | APINewsChannel + | APIGuildStoreChannel + | APIVoiceChannel + | APIGuildCategoryChannel + | APIThreadChannel + | APINewsChannel; + /** * https://discord.com/developers/docs/resources/channel#channel-object-channel-types */ diff --git a/rest/v8/guild.ts b/rest/v8/guild.ts index fdf8f381b..88e790f85 100644 --- a/rest/v8/guild.ts +++ b/rest/v8/guild.ts @@ -2,7 +2,9 @@ import type { Permissions, Snowflake } from '../../globals'; import type { APIBan, APIChannel, + APIDMChannel, APIExtendedInvite, + APIGroupDMChannel, APIGuild, APIGuildIntegration, APIGuildMember, @@ -25,6 +27,7 @@ import type { Nullable, StrictPartial, StrictRequired, + UnionToIntersection, } from '../../utils/internals'; import type { RESTPutAPIChannelPermissionJSONBody } from './channel'; @@ -32,8 +35,12 @@ export interface APIGuildCreateOverwrite extends RESTPutAPIChannelPermissionJSON id: number | string; } +export type APIGuildChannelResolvable = Exclude; export type APIGuildCreatePartialChannel = StrictPartial< - Pick + Pick< + UnionToIntersection, + 'type' | 'topic' | 'nsfw' | 'bitrate' | 'user_limit' | 'rate_limit_per_user' + > > & AddUndefinedToPossiblyUndefinedPropertiesOfInterface<{ name: string; diff --git a/rest/v9/guild.ts b/rest/v9/guild.ts index e95ef2ebc..82b3a34d5 100644 --- a/rest/v9/guild.ts +++ b/rest/v9/guild.ts @@ -20,12 +20,15 @@ import type { GuildSystemChannelFlags, GuildVerificationLevel, GuildWidgetStyle, + APIDMChannel, + APIGroupDMChannel, } from '../../payloads/v9/index'; import type { AddUndefinedToPossiblyUndefinedPropertiesOfInterface, Nullable, StrictPartial, StrictRequired, + UnionToIntersection, } from '../../utils/internals'; import type { RESTPutAPIChannelPermissionJSONBody } from './channel'; @@ -33,8 +36,12 @@ export interface APIGuildCreateOverwrite extends RESTPutAPIChannelPermissionJSON id: number | string; } +export type APIGuildChannelResolvable = Exclude; export type APIGuildCreatePartialChannel = StrictPartial< - Pick + Pick< + UnionToIntersection, + 'type' | 'topic' | 'nsfw' | 'bitrate' | 'user_limit' | 'rate_limit_per_user' + > > & AddUndefinedToPossiblyUndefinedPropertiesOfInterface<{ name: string; diff --git a/utils/internals.ts b/utils/internals.ts index 305ded2e8..fea21fab8 100644 --- a/utils/internals.ts +++ b/utils/internals.ts @@ -13,3 +13,5 @@ export type AddUndefinedToPossiblyUndefinedPropertiesOfInterface = { export type StrictPartial = AddUndefinedToPossiblyUndefinedPropertiesOfInterface>; export type StrictRequired = Required<{ [K in keyof Base]: Exclude }>; + +export type UnionToIntersection = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never;