types: use readonly array / collection types for user input (#10045)

* types: use readonly arrays

* chore: check on interface properties

* chore: ReadonlyCollection

* chore: exclude EventEmitter methods

* chore: resolve false positive
This commit is contained in:
Almeida
2024-02-23 00:29:06 +00:00
committed by GitHub
parent 8c2ababa78
commit bcd4c2cb23
3 changed files with 172 additions and 112 deletions

View File

@@ -204,6 +204,9 @@
{
"files": ["typings/*.ts", "scripts/*.mjs"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/naming-convention": [
@@ -216,6 +219,33 @@
"match": true
}
}
],
"no-restricted-syntax": [
2,
{
"selector": "MethodDefinition[key.name!=on][key.name!=once][key.name!=off] > TSEmptyBodyFunctionExpression > Identifier :not(TSTypeOperator[operator=readonly]) > TSArrayType",
"message": "Array parameters on methods must be readonly"
},
{
"selector": "MethodDefinition > TSEmptyBodyFunctionExpression > Identifier TSTypeReference > Identifier[name=Collection]",
"message": "Parameters of type Collection on methods must use ReadonlyCollection"
},
{
"selector": "TSDeclareFunction > Identifier :not(TSTypeOperator[operator=readonly]) > TSArrayType",
"message": "Array parameters on functions must be readonly"
},
{
"selector": "TSDeclareFunction Identifier TSTypeReference > Identifier[name=Collection]",
"message": "Parameters of type Collection on functions must use ReadonlyCollection"
},
{
"selector": "TSInterfaceDeclaration TSPropertySignature :not(TSTypeOperator[operator=readonly]) > TSArrayType",
"message": "Array properties on interfaces must be readonly"
},
{
"selector": "TSInterfaceDeclaration TSPropertySignature TSTypeReference > Identifier[name=Collection]",
"message": "Interface properties of type Collection must use ReadonlyCollection"
}
]
}
}

View File

@@ -305,7 +305,7 @@ export type ActionRowComponent = MessageActionRowComponent | ModalActionRowCompo
export interface ActionRowData<ComponentType extends JSONEncodable<APIActionRowComponentTypes> | ActionRowComponentData>
extends BaseComponentData {
components: ComponentType[];
components: readonly ComponentType[];
}
export class ActionRowBuilder<
@@ -395,23 +395,26 @@ export class AutoModerationRule extends Base {
public delete(reason?: string): Promise<void>;
public setName(name: string, reason?: string): Promise<AutoModerationRule>;
public setEventType(eventType: AutoModerationRuleEventType, reason?: string): Promise<AutoModerationRule>;
public setKeywordFilter(keywordFilter: string[], reason?: string): Promise<AutoModerationRule>;
public setRegexPatterns(regexPatterns: string[], reason?: string): Promise<AutoModerationRule>;
public setPresets(presets: AutoModerationRuleKeywordPresetType[], reason?: string): Promise<AutoModerationRule>;
public setAllowList(allowList: string[], reason?: string): Promise<AutoModerationRule>;
public setKeywordFilter(keywordFilter: readonly string[], reason?: string): Promise<AutoModerationRule>;
public setRegexPatterns(regexPatterns: readonly string[], reason?: string): Promise<AutoModerationRule>;
public setPresets(
presets: readonly AutoModerationRuleKeywordPresetType[],
reason?: string,
): Promise<AutoModerationRule>;
public setAllowList(allowList: readonly string[], reason?: string): Promise<AutoModerationRule>;
public setMentionTotalLimit(mentionTotalLimit: number, reason?: string): Promise<AutoModerationRule>;
public setMentionRaidProtectionEnabled(
mentionRaidProtectionEnabled: boolean,
reason?: string,
): Promise<AutoModerationRule>;
public setActions(actions: AutoModerationActionOptions[], reason?: string): Promise<AutoModerationRule>;
public setActions(actions: readonly AutoModerationActionOptions[], reason?: string): Promise<AutoModerationRule>;
public setEnabled(enabled?: boolean, reason?: string): Promise<AutoModerationRule>;
public setExemptRoles(
roles: Collection<Snowflake, Role> | RoleResolvable[],
roles: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[],
reason?: string,
): Promise<AutoModerationRule>;
public setExemptChannels(
channels: Collection<Snowflake, GuildBasedChannel> | GuildChannelResolvable[],
channels: ReadonlyCollection<Snowflake, GuildBasedChannel> | readonly GuildChannelResolvable[],
reason?: string,
): Promise<AutoModerationRule>;
}
@@ -469,14 +472,19 @@ export class ApplicationCommand<PermissionsFetchType = {}> extends Base {
defaultMemberPermissions: PermissionResolvable | null,
): Promise<ApplicationCommand<PermissionsFetchType>>;
public setDMPermission(dmPermission?: boolean): Promise<ApplicationCommand<PermissionsFetchType>>;
public setOptions(options: ApplicationCommandOptionData[]): Promise<ApplicationCommand<PermissionsFetchType>>;
public setOptions(
options: readonly ApplicationCommandOptionData[],
): Promise<ApplicationCommand<PermissionsFetchType>>;
public equals(
command: ApplicationCommand | ApplicationCommandData | RawApplicationCommandData,
enforceOptionOrder?: boolean,
): boolean;
public static optionsEqual(
existing: ApplicationCommandOption[],
options: ApplicationCommandOption[] | ApplicationCommandOptionData[] | APIApplicationCommandOption[],
existing: readonly ApplicationCommandOption[],
options:
| readonly ApplicationCommandOption[]
| readonly ApplicationCommandOptionData[]
| readonly APIApplicationCommandOption[],
enforceOptionOrder?: boolean,
): boolean;
private static _optionEquals(
@@ -862,7 +870,7 @@ export interface EmbedData {
thumbnail?: EmbedAssetData;
provider?: APIEmbedProvider;
author?: EmbedAuthorData;
fields?: APIEmbedField[];
fields?: readonly APIEmbedField[];
video?: EmbedAssetData;
}
@@ -1062,7 +1070,7 @@ export class ClientApplication extends Application {
public fetchRoleConnectionMetadataRecords(): Promise<ApplicationRoleConnectionMetadata[]>;
public fetchSKUs(): Promise<Collection<Snowflake, SKU>>;
public editRoleConnectionMetadataRecords(
records: ApplicationRoleConnectionMetadataEditOptions[],
records: readonly ApplicationRoleConnectionMetadataEditOptions[],
): Promise<ApplicationRoleConnectionMetadata[]>;
}
@@ -1080,10 +1088,10 @@ export class ClientUser extends User {
public edit(options: ClientUserEditOptions): Promise<this>;
public setActivity(options?: ActivityOptions): ClientPresence;
public setActivity(name: string, options?: Omit<ActivityOptions, 'name'>): ClientPresence;
public setAFK(afk?: boolean, shardId?: number | number[]): ClientPresence;
public setAFK(afk?: boolean, shardId?: number | readonly number[]): ClientPresence;
public setAvatar(avatar: BufferResolvable | Base64Resolvable | null): Promise<this>;
public setPresence(data: PresenceData): ClientPresence;
public setStatus(status: PresenceStatusData, shardId?: number | number[]): ClientPresence;
public setStatus(status: PresenceStatusData, shardId?: number | readonly number[]): ClientPresence;
public setUsername(username: string): Promise<this>;
}
@@ -1109,7 +1117,7 @@ export interface CollectorEventTypes<Key, Value, Extras extends unknown[] = []>
collect: [Value, ...Extras];
ignore: [Value, ...Extras];
dispose: [Value, ...Extras];
end: [collected: Collection<Key, Value>, reason: string];
end: [collected: ReadonlyCollection<Key, Value>, reason: string];
}
export abstract class Collector<Key, Value, Extras extends unknown[] = []> extends EventEmitter {
@@ -1175,13 +1183,13 @@ export class AutocompleteInteraction<Cached extends CacheType = CacheType> exten
public inGuild(): this is AutocompleteInteraction<'raw' | 'cached'>;
public inCachedGuild(): this is AutocompleteInteraction<'cached'>;
public inRawGuild(): this is AutocompleteInteraction<'raw'>;
public respond(options: ApplicationCommandOptionChoiceData[]): Promise<void>;
public respond(options: readonly ApplicationCommandOptionChoiceData[]): Promise<void>;
}
export class CommandInteractionOptionResolver<Cached extends CacheType = CacheType> {
private constructor(
client: Client<true>,
options: CommandInteractionOption[],
options: readonly CommandInteractionOption[],
resolved: CommandInteractionResolvedData,
);
public readonly client: Client;
@@ -1192,14 +1200,14 @@ export class CommandInteractionOptionResolver<Cached extends CacheType = CacheTy
private _subcommand: string | null;
private _getTypedOption(
name: string,
allowedTypes: ApplicationCommandOptionType[],
properties: (keyof ApplicationCommandOption)[],
allowedTypes: readonly ApplicationCommandOptionType[],
properties: readonly (keyof ApplicationCommandOption)[],
required: true,
): CommandInteractionOption<Cached>;
private _getTypedOption(
name: string,
allowedTypes: ApplicationCommandOptionType[],
properties: (keyof ApplicationCommandOption)[],
allowedTypes: readonly ApplicationCommandOptionType[],
properties: readonly (keyof ApplicationCommandOption)[],
required: boolean,
): CommandInteractionOption<Cached> | null;
@@ -1923,11 +1931,17 @@ export class InteractionCollector<Interaction extends CollectedInteraction> exte
public empty(): void;
public dispose(interaction: Interaction): Snowflake;
public on(event: 'collect' | 'dispose' | 'ignore', listener: (interaction: Interaction) => void): this;
public on(event: 'end', listener: (collected: Collection<Snowflake, Interaction>, reason: string) => void): this;
public on(
event: 'end',
listener: (collected: ReadonlyCollection<Snowflake, Interaction>, reason: string) => void,
): this;
public on(event: string, listener: (...args: any[]) => void): this;
public once(event: 'collect' | 'dispose' | 'ignore', listener: (interaction: Interaction) => void): this;
public once(event: 'end', listener: (collected: Collection<Snowflake, Interaction>, reason: string) => void): this;
public once(
event: 'end',
listener: (collected: ReadonlyCollection<Snowflake, Interaction>, reason: string) => void,
): this;
public once(event: string, listener: (...args: any[]) => void): this;
}
@@ -2268,8 +2282,8 @@ export class MessageFlagsBitField extends BitField<MessageFlagsString> {
export class MessageMentions<InGuild extends boolean = boolean> {
private constructor(
message: Message,
users: APIUser[] | Collection<Snowflake, User>,
roles: Snowflake[] | Collection<Snowflake, Role>,
users: readonly APIUser[] | ReadonlyCollection<Snowflake, User>,
roles: readonly Snowflake[] | ReadonlyCollection<Snowflake, Role>,
everyone: boolean,
repliedUser?: APIUser | User,
);
@@ -2354,7 +2368,7 @@ export class MessageReaction {
export interface ModalComponentData {
customId: string;
title: string;
components: (
components: readonly (
| JSONEncodable<APIActionRowComponent<APIModalActionRowComponent>>
| ActionRowData<ModalActionRowComponentData>
)[];
@@ -2372,11 +2386,11 @@ export interface TextInputModalData extends BaseModalData {
export interface ActionRowModalData {
type: ComponentType.ActionRow;
components: TextInputModalData[];
components: readonly TextInputModalData[];
}
export class ModalSubmitFields {
constructor(components: ModalActionRowComponent[][]);
constructor(components: readonly (readonly ModalActionRowComponent[])[]);
public components: ActionRowModalData[];
public fields: Collection<string, ModalActionRowComponent>;
public getField<Type extends ComponentType>(customId: string, type: Type): { type: Type } & TextInputModalData;
@@ -2502,7 +2516,7 @@ export abstract class ThreadOnlyChannel extends GuildChannel {
public nsfw: boolean;
public topic: string | null;
public defaultSortOrder: SortOrderType | null;
public setAvailableTags(tags: GuildForumTagData[], reason?: string): Promise<this>;
public setAvailableTags(tags: readonly GuildForumTagData[], reason?: string): Promise<this>;
public setDefaultReactionEmoji(emojiId: DefaultReactionEmoji | null, reason?: string): Promise<this>;
public setDefaultThreadRateLimitPerUser(rateLimit: number, reason?: string): Promise<this>;
public createInvite(options?: InviteCreateOptions): Promise<Invite>;
@@ -2591,7 +2605,10 @@ export class ReactionCollector extends Collector<Snowflake | string, MessageReac
event: 'collect' | 'dispose' | 'remove' | 'ignore',
listener: (reaction: MessageReaction, user: User) => void,
): this;
public on(event: 'end', listener: (collected: Collection<Snowflake, MessageReaction>, reason: string) => void): this;
public on(
event: 'end',
listener: (collected: ReadonlyCollection<Snowflake, MessageReaction>, reason: string) => void,
): this;
public on(event: string, listener: (...args: any[]) => void): this;
public once(
@@ -2600,7 +2617,7 @@ export class ReactionCollector extends Collector<Snowflake | string, MessageReac
): this;
public once(
event: 'end',
listener: (collected: Collection<Snowflake, MessageReaction>, reason: string) => void,
listener: (collected: ReadonlyCollection<Snowflake, MessageReaction>, reason: string) => void,
): this;
public once(event: string, listener: (...args: any[]) => void): this;
}
@@ -2883,8 +2900,8 @@ export class ShardClientUtil {
export class ShardingManager extends EventEmitter {
public constructor(file: string, options?: ShardingManagerOptions);
private _performOnShards(method: string, args: unknown[]): Promise<unknown[]>;
private _performOnShards(method: string, args: unknown[], shard: number): Promise<unknown>;
private _performOnShards(method: string, args: readonly unknown[]): Promise<unknown[]>;
private _performOnShards(method: string, args: readonly unknown[], shard: number): Promise<unknown>;
public file: string;
public respawn: boolean;
@@ -3208,7 +3225,7 @@ export class ThreadChannel<ThreadOnly extends boolean = boolean> extends BaseCha
public setLocked(locked?: boolean, reason?: string): Promise<AnyThreadChannel>;
public setName(name: string, reason?: string): Promise<AnyThreadChannel>;
// The following 3 methods can only be run on forum threads.
public setAppliedTags(appliedTags: Snowflake[], reason?: string): Promise<ThreadChannel<true>>;
public setAppliedTags(appliedTags: readonly Snowflake[], reason?: string): Promise<ThreadChannel<true>>;
public pin(reason?: string): Promise<ThreadChannel<true>>;
public unpin(reason?: string): Promise<ThreadChannel<true>>;
public toString(): ChannelMention;
@@ -3324,7 +3341,7 @@ export class UserFlagsBitField extends BitField<UserFlagsString> {
export function basename(path: string, ext?: string): string;
export function cleanContent(str: string, channel: TextBasedChannel): string;
export function discordSort<Key, Value extends { rawPosition: number; id: Snowflake }>(
collection: Collection<Key, Value>,
collection: ReadonlyCollection<Key, Value>,
): Collection<Key, Value>;
export function cleanCodeBlockContent(text: string): string;
export function fetchRecommendedShardCount(token: string, options?: FetchRecommendedShardCountOptions): Promise<number>;
@@ -3334,7 +3351,13 @@ export function makeError(obj: MakeErrorOptions): Error;
/** @internal */
export function makePlainError(err: Error): MakeErrorOptions;
/** @internal */
export function moveElementInArray(array: unknown[], element: unknown, newIndex: number, offset?: boolean): number;
export function moveElementInArray(
// eslint-disable-next-line no-restricted-syntax
array: unknown[],
element: unknown,
newIndex: number,
offset?: boolean,
): number;
export function parseEmoji(text: string): PartialEmoji | null;
export function resolveColor(color: ColorResolvable): number;
/** @internal */
@@ -3347,7 +3370,7 @@ export function setPosition<Item extends Channel | Role>(
item: Item,
position: number,
relative: boolean,
sorted: Collection<Snowflake, Item>,
sorted: ReadonlyCollection<Snowflake, Item>,
client: Client<true>,
route: string,
reason?: string,
@@ -4146,7 +4169,7 @@ export class GuildApplicationCommandManager extends ApplicationCommandManager<Ap
id?: undefined,
options?: FetchGuildApplicationCommandFetchOptions,
): Promise<Collection<Snowflake, ApplicationCommand>>;
public set(commands: ApplicationCommandDataResolvable[]): Promise<Collection<Snowflake, ApplicationCommand>>;
public set(commands: readonly ApplicationCommandDataResolvable[]): Promise<Collection<Snowflake, ApplicationCommand>>;
}
export type MappedGuildChannelTypes = {
@@ -4204,11 +4227,11 @@ export class GuildEmojiRoleManager extends DataManager<Snowflake, Role, RoleReso
public emoji: GuildEmoji;
public guild: Guild;
public add(
roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection<Snowflake, Role>,
roleOrRoles: RoleResolvable | readonly RoleResolvable[] | ReadonlyCollection<Snowflake, Role>,
): Promise<GuildEmoji>;
public set(roles: readonly RoleResolvable[] | Collection<Snowflake, Role>): Promise<GuildEmoji>;
public set(roles: readonly RoleResolvable[] | ReadonlyCollection<Snowflake, Role>): Promise<GuildEmoji>;
public remove(
roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection<Snowflake, Role>,
roleOrRoles: RoleResolvable | readonly RoleResolvable[] | ReadonlyCollection<Snowflake, Role>,
): Promise<GuildEmoji>;
}
@@ -4319,12 +4342,15 @@ export class GuildMemberRoleManager extends DataManager<Snowflake, Role, RoleRes
public guild: Guild;
public add(
roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection<Snowflake, Role>,
roleOrRoles: RoleResolvable | readonly RoleResolvable[] | ReadonlyCollection<Snowflake, Role>,
reason?: string,
): Promise<GuildMember>;
public set(
roles: readonly RoleResolvable[] | ReadonlyCollection<Snowflake, Role>,
reason?: string,
): Promise<GuildMember>;
public set(roles: readonly RoleResolvable[] | Collection<Snowflake, Role>, reason?: string): Promise<GuildMember>;
public remove(
roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection<Snowflake, Role>,
roleOrRoles: RoleResolvable | readonly RoleResolvable[] | ReadonlyCollection<Snowflake, Role>,
reason?: string,
): Promise<GuildMember>;
}
@@ -4365,7 +4391,7 @@ export class PermissionOverwriteManager extends CachedManager<
> {
private constructor(client: Client<true>, iterable?: Iterable<RawPermissionOverwriteData>);
public set(
overwrites: readonly OverwriteResolvable[] | Collection<Snowflake, OverwriteResolvable>,
overwrites: readonly OverwriteResolvable[] | ReadonlyCollection<Snowflake, OverwriteResolvable>,
reason?: string,
): Promise<NonThreadGuildBasedChannel>;
private upsert(
@@ -4575,7 +4601,7 @@ export interface ActivityOptions {
export interface AddGuildMemberOptions {
accessToken: string;
nick?: string;
roles?: Collection<Snowflake, Role> | RoleResolvable[];
roles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];
mute?: boolean;
deaf?: boolean;
force?: boolean;
@@ -4909,10 +4935,10 @@ export interface AutoModerationActionMetadata {
}
export interface AutoModerationTriggerMetadata {
keywordFilter: string[];
regexPatterns: string[];
presets: AutoModerationRuleKeywordPresetType[];
allowList: string[];
keywordFilter: readonly string[];
regexPatterns: readonly string[];
presets: readonly AutoModerationRuleKeywordPresetType[];
allowList: readonly string[];
mentionTotalLimit: number | null;
mentionRaidProtectionEnabled: boolean;
}
@@ -4929,11 +4955,11 @@ export interface AwaitModalSubmitOptions<Interaction extends ModalSubmitInteract
}
export interface AwaitMessagesOptions extends MessageCollectorOptions {
errors?: string[];
errors?: readonly string[];
}
export interface AwaitReactionsOptions extends ReactionCollectorOptions {
errors?: string[];
errors?: readonly string[];
}
export interface BanOptions {
@@ -5017,7 +5043,7 @@ export type CacheWithLimitsOptions = {
export interface CategoryCreateChannelOptions {
name: string;
permissionOverwrites?: OverwriteResolvable[] | Collection<Snowflake, OverwriteResolvable>;
permissionOverwrites?: readonly OverwriteResolvable[] | ReadonlyCollection<Snowflake, OverwriteResolvable>;
topic?: string;
type?: CategoryChannelType;
nsfw?: boolean;
@@ -5028,7 +5054,7 @@ export interface CategoryCreateChannelOptions {
rtcRegion?: string;
videoQualityMode?: VideoQualityMode;
defaultThreadRateLimitPerUser?: number;
availableTags?: GuildForumTagData[];
availableTags?: readonly GuildForumTagData[];
defaultReactionEmoji?: DefaultReactionEmoji;
defaultAutoArchiveDuration?: ThreadAutoArchiveDuration;
defaultSortOrder?: SortOrderType;
@@ -5102,9 +5128,9 @@ export interface ClientEvents {
guildMemberAvailable: [member: GuildMember | PartialGuildMember];
guildMemberRemove: [member: GuildMember | PartialGuildMember];
guildMembersChunk: [
members: Collection<Snowflake, GuildMember>,
members: ReadonlyCollection<Snowflake, GuildMember>,
guild: Guild,
data: { index: number; count: number; notFound: unknown[]; nonce: string | undefined },
data: { index: number; count: number; notFound: readonly unknown[]; nonce: string | undefined },
];
guildMemberUpdate: [oldMember: GuildMember | PartialGuildMember, newMember: GuildMember];
guildUpdate: [oldGuild: Guild, newGuild: Guild];
@@ -5114,10 +5140,13 @@ export interface ClientEvents {
messageDelete: [message: Message | PartialMessage];
messageReactionRemoveAll: [
message: Message | PartialMessage,
reactions: Collection<string | Snowflake, MessageReaction>,
reactions: ReadonlyCollection<string | Snowflake, MessageReaction>,
];
messageReactionRemoveEmoji: [reaction: MessageReaction | PartialMessageReaction];
messageDeleteBulk: [messages: Collection<Snowflake, Message | PartialMessage>, channel: GuildTextBasedChannel];
messageDeleteBulk: [
messages: ReadonlyCollection<Snowflake, Message | PartialMessage>,
channel: GuildTextBasedChannel,
];
messageReactionAdd: [reaction: MessageReaction | PartialMessageReaction, user: User | PartialUser];
messageReactionRemove: [reaction: MessageReaction | PartialMessageReaction, user: User | PartialUser];
messageUpdate: [oldMessage: Message | PartialMessage, newMessage: Message | PartialMessage];
@@ -5129,11 +5158,11 @@ export interface ClientEvents {
roleUpdate: [oldRole: Role, newRole: Role];
threadCreate: [thread: AnyThreadChannel, newlyCreated: boolean];
threadDelete: [thread: AnyThreadChannel];
threadListSync: [threads: Collection<Snowflake, AnyThreadChannel>, guild: Guild];
threadListSync: [threads: ReadonlyCollection<Snowflake, AnyThreadChannel>, guild: Guild];
threadMemberUpdate: [oldMember: ThreadMember, newMember: ThreadMember];
threadMembersUpdate: [
addedMembers: Collection<Snowflake, ThreadMember>,
removedMembers: Collection<Snowflake, ThreadMember | PartialThreadMember>,
addedMembers: ReadonlyCollection<Snowflake, ThreadMember>,
removedMembers: ReadonlyCollection<Snowflake, ThreadMember | PartialThreadMember>,
thread: AnyThreadChannel,
];
threadUpdate: [oldThread: AnyThreadChannel, newThread: AnyThreadChannel];
@@ -5170,12 +5199,12 @@ export interface ClientFetchInviteOptions {
}
export interface ClientOptions {
shards?: number | number[] | 'auto';
shards?: number | readonly number[] | 'auto';
shardCount?: number;
closeTimeout?: number;
makeCache?: CacheFactory;
allowedMentions?: MessageMentionOptions;
partials?: Partials[];
partials?: readonly Partials[];
failIfNotExists?: boolean;
presence?: PresenceData;
intents: BitFieldResolvable<GatewayIntentsString, number>;
@@ -5234,7 +5263,7 @@ export interface CommandInteractionOption<Cached extends CacheType = CacheType>
value?: string | number | boolean;
focused?: boolean;
autocomplete?: boolean;
options?: CommandInteractionOption[];
options?: readonly CommandInteractionOption[];
user?: User;
member?: CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>;
channel?: CacheTypeReducer<Cached, GuildBasedChannel, APIInteractionDataResolvedChannel>;
@@ -5244,12 +5273,12 @@ export interface CommandInteractionOption<Cached extends CacheType = CacheType>
}
export interface CommandInteractionResolvedData<Cached extends CacheType = CacheType> {
users?: Collection<Snowflake, User>;
members?: Collection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;
roles?: Collection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
channels?: Collection<Snowflake, CacheTypeReducer<Cached, Channel, APIInteractionDataResolvedChannel>>;
messages?: Collection<Snowflake, CacheTypeReducer<Cached, Message, APIMessage>>;
attachments?: Collection<Snowflake, Attachment>;
users?: ReadonlyCollection<Snowflake, User>;
members?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, GuildMember, APIInteractionDataResolvedGuildMember>>;
roles?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Role, APIRole>>;
channels?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Channel, APIInteractionDataResolvedChannel>>;
messages?: ReadonlyCollection<Snowflake, CacheTypeReducer<Cached, Message, APIMessage>>;
attachments?: ReadonlyCollection<Snowflake, Attachment>;
}
export interface AutocompleteFocusedOption extends Pick<CommandInteractionOption, 'name'> {
@@ -5498,8 +5527,8 @@ export interface FetchChannelOptions extends BaseFetchOptions {
}
export interface FetchedThreads {
threads: Collection<Snowflake, AnyThreadChannel>;
members: Collection<Snowflake, ThreadMember>;
threads: ReadonlyCollection<Snowflake, AnyThreadChannel>;
members: ReadonlyCollection<Snowflake, ThreadMember>;
}
export interface FetchedThreadsMore extends FetchedThreads {
@@ -5546,7 +5575,7 @@ export interface FetchMemberOptions extends BaseFetchOptions {
}
export interface FetchMembersOptions {
user?: UserResolvable | UserResolvable[];
user?: UserResolvable | readonly UserResolvable[];
query?: string;
limit?: number;
withPresences?: boolean;
@@ -5752,10 +5781,10 @@ export interface AutoModerationRuleCreateOptions {
eventType: AutoModerationRuleEventType;
triggerType: AutoModerationRuleTriggerType;
triggerMetadata?: AutoModerationTriggerMetadataOptions;
actions: AutoModerationActionOptions[];
actions: readonly AutoModerationActionOptions[];
enabled?: boolean;
exemptRoles?: Collection<Snowflake, Role> | RoleResolvable[];
exemptChannels?: Collection<Snowflake, GuildBasedChannel> | GuildChannelResolvable[];
exemptRoles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];
exemptChannels?: ReadonlyCollection<Snowflake, GuildBasedChannel> | readonly GuildChannelResolvable[];
reason?: string;
}
@@ -5799,11 +5828,11 @@ export interface GuildChannelEditOptions {
parent?: CategoryChannelResolvable | null;
rateLimitPerUser?: number;
lockPermissions?: boolean;
permissionOverwrites?: readonly OverwriteResolvable[] | Collection<Snowflake, OverwriteResolvable>;
permissionOverwrites?: readonly OverwriteResolvable[] | ReadonlyCollection<Snowflake, OverwriteResolvable>;
defaultAutoArchiveDuration?: ThreadAutoArchiveDuration;
rtcRegion?: string | null;
videoQualityMode?: VideoQualityMode | null;
availableTags?: GuildForumTagData[];
availableTags?: readonly GuildForumTagData[];
defaultReactionEmoji?: DefaultReactionEmoji | null;
defaultThreadRateLimitPerUser?: number;
flags?: ChannelFlagsResolvable;
@@ -5823,8 +5852,8 @@ export interface GuildCreateOptions {
verificationLevel?: GuildVerificationLevel;
defaultMessageNotifications?: GuildDefaultMessageNotifications;
explicitContentFilter?: GuildExplicitContentFilter;
roles?: PartialRoleData[];
channels?: PartialChannelData[];
roles?: readonly PartialRoleData[];
channels?: readonly PartialChannelData[];
afkChannelId?: Snowflake | number;
afkTimeout?: number;
systemChannelId?: Snowflake | number;
@@ -5854,7 +5883,7 @@ export interface GuildEditOptions {
publicUpdatesChannel?: TextChannelResolvable | null;
safetyAlertsChannel?: TextChannelResolvable | null;
preferredLocale?: Locale | null;
features?: `${GuildFeature}`[];
features?: readonly `${GuildFeature}`[];
description?: string | null;
premiumProgressBarEnabled?: boolean;
reason?: string;
@@ -5863,13 +5892,13 @@ export interface GuildEditOptions {
export interface GuildEmojiCreateOptions {
attachment: BufferResolvable | Base64Resolvable;
name: string;
roles?: Collection<Snowflake, Role> | RoleResolvable[];
roles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];
reason?: string;
}
export interface GuildEmojiEditOptions {
name?: string;
roles?: Collection<Snowflake, Role> | RoleResolvable[];
roles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];
reason?: string;
}
@@ -5890,7 +5919,7 @@ export interface GuildStickerEditOptions {
export interface GuildMemberEditOptions {
nick?: string | null;
roles?: Collection<Snowflake, Role> | readonly RoleResolvable[];
roles?: ReadonlyCollection<Snowflake, Role> | readonly RoleResolvable[];
mute?: boolean;
deaf?: boolean;
channel?: GuildVoiceChannelResolvable | null;
@@ -5908,7 +5937,7 @@ export interface GuildPruneMembersOptions {
days?: number;
dry?: boolean;
reason?: string;
roles?: RoleResolvable[];
roles?: readonly RoleResolvable[];
}
export interface GuildWidgetSettingsData {
@@ -6074,7 +6103,7 @@ export interface InviteGenerationOptions {
permissions?: PermissionResolvable;
guild?: GuildResolvable;
disableGuildSelect?: boolean;
scopes: OAuth2Scopes[];
scopes: readonly OAuth2Scopes[];
}
export type GuildInvitableChannelResolvable =
@@ -6194,9 +6223,9 @@ export interface MessageMentionsHasOptions {
}
export interface MessageMentionOptions {
parse?: MessageMentionTypes[];
roles?: Snowflake[];
users?: Snowflake[];
parse?: readonly MessageMentionTypes[];
roles?: readonly Snowflake[];
users?: readonly Snowflake[];
repliedUser?: boolean;
}
@@ -6204,9 +6233,9 @@ export type MessageMentionTypes = 'roles' | 'users' | 'everyone';
export interface BaseMessageOptions {
content?: string;
embeds?: (JSONEncodable<APIEmbed> | APIEmbed)[];
embeds?: readonly (JSONEncodable<APIEmbed> | APIEmbed)[];
allowedMentions?: MessageMentionOptions;
files?: (
files?: readonly (
| BufferResolvable
| Stream
| JSONEncodable<APIAttachment>
@@ -6214,7 +6243,7 @@ export interface BaseMessageOptions {
| AttachmentBuilder
| AttachmentPayload
)[];
components?: (
components?: readonly (
| JSONEncodable<APIActionRowComponent<APIMessageActionRowComponent>>
| ActionRowData<MessageActionRowComponentData | MessageActionRowComponentBuilder>
| APIActionRowComponent<APIMessageActionRowComponent>
@@ -6226,7 +6255,7 @@ export interface MessageCreateOptions extends BaseMessageOptions {
nonce?: string | number;
enforceNonce?: boolean;
reply?: ReplyOptions;
stickers?: StickerResolvable[];
stickers?: readonly StickerResolvable[];
flags?: BitFieldResolvable<
Extract<MessageFlagsString, 'SuppressEmbeds' | 'SuppressNotifications'>,
MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
@@ -6243,7 +6272,7 @@ export interface MessageEditAttachmentData {
export interface MessageEditOptions extends Omit<BaseMessageOptions, 'content'> {
content?: string | null;
attachments?: (Attachment | MessageEditAttachmentData)[];
attachments?: readonly (Attachment | MessageEditAttachmentData)[];
flags?: BitFieldResolvable<Extract<MessageFlagsString, 'SuppressEmbeds'>, MessageFlags.SuppressEmbeds>;
}
@@ -6267,7 +6296,7 @@ export interface BaseSelectMenuComponentData extends BaseComponentData {
export interface StringSelectMenuComponentData extends BaseSelectMenuComponentData {
type: ComponentType.StringSelect;
options: SelectMenuComponentOptionData[];
options: readonly SelectMenuComponentOptionData[];
}
export interface UserSelectMenuComponentData extends BaseSelectMenuComponentData {
@@ -6284,7 +6313,7 @@ export interface MentionableSelectMenuComponentData extends BaseSelectMenuCompon
export interface ChannelSelectMenuComponentData extends BaseSelectMenuComponentData {
type: ComponentType.ChannelSelect;
channelTypes?: ChannelType[];
channelTypes?: readonly ChannelType[];
}
export interface MessageSelectOption {
@@ -6364,8 +6393,8 @@ export interface PartialRecipient {
export interface PresenceData {
status?: PresenceStatusData;
afk?: boolean;
activities?: ActivitiesOptions[];
shardId?: number | number[];
activities?: readonly ActivitiesOptions[];
shardId?: number | readonly number[];
}
export type PresenceResolvable = Presence | UserResolvable | Snowflake;
@@ -6381,7 +6410,7 @@ export interface PartialChannelData {
userLimit?: number;
rtcRegion?: string | null;
videoQualityMode?: VideoQualityMode;
permissionOverwrites?: PartialOverwriteData[];
permissionOverwrites?: readonly PartialOverwriteData[];
rateLimitPerUser?: number;
}
@@ -6528,13 +6557,13 @@ export type ShardingManagerMode = 'process' | 'worker';
export interface ShardingManagerOptions {
totalShards?: number | 'auto';
shardList?: number[] | 'auto';
shardList?: readonly number[] | 'auto';
mode?: ShardingManagerMode;
respawn?: boolean;
silent?: boolean;
shardArgs?: string[];
shardArgs?: readonly string[];
token?: string;
execArgv?: string[];
execArgv?: readonly string[];
}
export { Snowflake };
@@ -6661,7 +6690,7 @@ export interface GuildTextThreadCreateOptions<AllowedThreadType> extends StartTh
export interface GuildForumThreadCreateOptions extends StartThreadOptions {
message: GuildForumThreadMessageCreateOptions | MessagePayload;
appliedTags?: Snowflake[];
appliedTags?: readonly Snowflake[];
}
export interface ThreadEditOptions {
@@ -6671,7 +6700,7 @@ export interface ThreadEditOptions {
rateLimitPerUser?: number;
locked?: boolean;
invitable?: boolean;
appliedTags?: Snowflake[];
appliedTags?: readonly Snowflake[];
flags?: ChannelFlagsResolvable;
reason?: string;
}
@@ -6738,7 +6767,7 @@ export interface WebhookMessageCreateOptions extends Omit<MessageCreateOptions,
avatarURL?: string;
threadId?: Snowflake;
threadName?: string;
appliedTags?: Snowflake[];
appliedTags?: readonly Snowflake[];
}
export interface WebSocketOptions {
@@ -6767,7 +6796,7 @@ export interface WelcomeChannelData {
export interface WelcomeScreenEditOptions {
enabled?: boolean;
description?: string;
welcomeChannels?: WelcomeChannelData[];
welcomeChannels?: readonly WelcomeChannelData[];
}
export interface ClientApplicationEditOptions {
@@ -6783,7 +6812,7 @@ export interface ClientApplicationEditOptions {
}
export interface ClientApplicationInstallParams {
scopes: OAuth2Scopes[];
scopes: readonly OAuth2Scopes[];
permissions: Readonly<PermissionsBitField>;
}

View File

@@ -193,6 +193,7 @@ import {
} from '.';
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
import { ReadonlyCollection } from '@discordjs/collection';
// Test type transformation:
declare const serialize: <Value>(value: Value) => Serialized<Value>;
@@ -1171,8 +1172,8 @@ client.on('threadMembersUpdate', (addedMembers, removedMembers, thread) => {
expectType<Client<true>>(addedMembers.first()!.client);
expectType<Client<true>>(removedMembers.first()!.client);
expectType<Client<true>>(thread.client);
expectType<Collection<Snowflake, ThreadMember>>(addedMembers);
expectType<Collection<Snowflake, ThreadMember | PartialThreadMember>>(removedMembers);
expectType<ReadonlyCollection<Snowflake, ThreadMember>>(addedMembers);
expectType<ReadonlyCollection<Snowflake, ThreadMember | PartialThreadMember>>(removedMembers);
expectType<AnyThreadChannel>(thread);
const left = removedMembers.first();
if (!left) return;
@@ -1990,7 +1991,7 @@ client.on('interactionCreate', async interaction => {
const requiredOption = interaction.options.get('name', true);
expectType<CommandInteractionOption | null>(optionalOption);
expectType<CommandInteractionOption>(requiredOption);
expectType<CommandInteractionOption[] | undefined>(requiredOption.options);
expectType<readonly CommandInteractionOption[] | undefined>(requiredOption.options);
expectType<string | null>(interaction.options.getString('name', booleanValue));
expectType<string | null>(interaction.options.getString('name', false));
@@ -2082,7 +2083,7 @@ collector.on('dispose', (vals, ...other) => {
});
collector.on('end', (collection, reason) => {
expectType<Collection<string, Interaction>>(collection);
expectType<ReadonlyCollection<string, Interaction>>(collection);
expectType<string>(reason);
});