CI: Use tsd for Testing Types (#6983)

Co-authored-by: Noel <buechler.noel@outlook.com>
This commit is contained in:
Suneet Tipirneni
2021-11-23 12:00:58 -05:00
committed by GitHub
parent 2a0dedf3e9
commit 9f3bf2927c
5 changed files with 1035 additions and 332 deletions

1
.eslintignore Normal file
View File

@@ -0,0 +1 @@
/typings/**/*

View File

@@ -58,7 +58,7 @@ jobs:
- name: Register Problem Matcher - name: Register Problem Matcher
run: echo "##[add-matcher].github/tsc.json" run: echo "##[add-matcher].github/tsc.json"
- name: Run TypeScript compiler - name: Run Type Tests
run: npm run test:typescript run: npm run test:typescript
docs: docs:

795
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"description": "A powerful library for interacting with the Discord API", "description": "A powerful library for interacting with the Discord API",
"scripts": { "scripts": {
"test": "npm run lint && npm run docs:test && npm run lint:typings && npm run test:typescript", "test": "npm run lint && npm run docs:test && npm run lint:typings && npm run test:typescript",
"test:typescript": "tsc --noEmit", "test:typescript": "tsc --noEmit && tsd",
"lint": "eslint src", "lint": "eslint src",
"lint:fix": "eslint src --fix", "lint:fix": "eslint src --fix",
"lint:typings": "tslint typings/index.d.ts", "lint:typings": "tslint typings/index.d.ts",
@@ -76,6 +76,7 @@
"jest": "^27.3.1", "jest": "^27.3.1",
"lint-staged": "^11.2.6", "lint-staged": "^11.2.6",
"prettier": "^2.4.1", "prettier": "^2.4.1",
"tsd": "^0.18.0",
"tslint": "^6.1.3", "tslint": "^6.1.3",
"typescript": "^4.5.2" "typescript": "^4.5.2"
}, },

View File

@@ -1,6 +1,5 @@
import type { ChildProcess } from 'child_process'; import type { ChildProcess } from 'child_process';
import type { import type {
APIGuildMember,
APIInteractionGuildMember, APIInteractionGuildMember,
APIMessage, APIMessage,
APIPartialChannel, APIPartialChannel,
@@ -11,11 +10,8 @@ import type {
} from 'discord-api-types/v9'; } from 'discord-api-types/v9';
import { import {
ApplicationCommand, ApplicationCommand,
ApplicationCommandChannelOptionData,
ApplicationCommandChoicesData,
ApplicationCommandData, ApplicationCommandData,
ApplicationCommandManager, ApplicationCommandManager,
ApplicationCommandNonOptionsData,
ApplicationCommandOptionData, ApplicationCommandOptionData,
ApplicationCommandResolvable, ApplicationCommandResolvable,
ApplicationCommandSubCommandData, ApplicationCommandSubCommandData,
@@ -81,12 +77,15 @@ import {
User, User,
VoiceChannel, VoiceChannel,
Shard, Shard,
ApplicationCommandAutocompleteOption,
ApplicationCommandNumericOptionData,
WebSocketShard, WebSocketShard,
Collector, Collector,
} from '.'; } from '.';
import type { ApplicationCommandOptionTypes } from './enums'; import type { ApplicationCommandOptionTypes } from './enums';
import { expectAssignable, expectDeprecated, expectNotAssignable, expectNotType, expectType } from 'tsd';
// Test type transformation:
declare const serialize: <T>(value: T) => Serialized<T>;
declare const notPropertyOf: <T, P extends PropertyKey>(value: T, property: P & Exclude<P, keyof T>) => void;
const client: Client = new Client({ const client: Client = new Client({
intents: Intents.FLAGS.GUILDS, intents: Intents.FLAGS.GUILDS,
@@ -115,8 +114,10 @@ client.on('ready', async () => {
console.log(`Client is logged in as ${client.user!.tag} and ready!`); console.log(`Client is logged in as ${client.user!.tag} and ready!`);
// Test fetching all global commands and ones from one guild // Test fetching all global commands and ones from one guild
assertType<Collection<string, ApplicationCommand>>(await client.application!.commands.fetch()); expectType<Collection<string, ApplicationCommand<{ guild: GuildResolvable }>>>(
assertType<Collection<string, ApplicationCommand>>( await client.application!.commands.fetch(),
);
expectType<Collection<string, ApplicationCommand<{ guild: GuildResolvable }>>>(
await client.application!.commands.fetch({ guildId: testGuildId }), await client.application!.commands.fetch({ guildId: testGuildId }),
); );
@@ -449,78 +450,16 @@ client.on('ready', async () => {
}); });
}); });
// This is to check that stuff is the right type
declare const assertIsPromiseMember: (m: Promise<GuildMember>) => void;
const baseCommandOptionData = {
name: 'test',
description: 'test',
};
assertType<ApplicationCommandOptionData>({
...baseCommandOptionData,
type: 'STRING',
autocomplete: true,
// @ts-expect-error
choices: [],
});
assertType<ApplicationCommandOptionData>({
...baseCommandOptionData,
type: 'STRING',
autocomplete: false,
choices: [],
});
assertType<ApplicationCommandOptionData>({
...baseCommandOptionData,
type: 'STRING',
choices: [],
});
assertType<ApplicationCommandOptionData>({
...baseCommandOptionData,
type: 'NUMBER',
autocomplete: true,
// @ts-expect-error
choices: [],
});
assertType<ApplicationCommandOptionData>({
...baseCommandOptionData,
type: 'INTEGER',
autocomplete: true,
// @ts-expect-error
choices: [],
});
assertType<ApplicationCommandOptionData>({
...baseCommandOptionData,
type: 'NUMBER',
autocomplete: true,
});
assertType<ApplicationCommandOptionData>({
...baseCommandOptionData,
type: 'STRING',
autocomplete: true,
});
assertType<ApplicationCommandOptionData>({
...baseCommandOptionData,
type: 'INTEGER',
autocomplete: true,
});
client.on('guildCreate', async g => { client.on('guildCreate', async g => {
const channel = g.channels.cache.random(); const channel = g.channels.cache.random();
if (!channel) return; if (!channel) return;
if (channel.isThread()) { if (channel.isThread()) {
const fetchedMember = await channel.members.fetch('12345678'); const fetchedMember = await channel.members.fetch('12345678');
assertType<ThreadMember>(fetchedMember); expectType<ThreadMember>(fetchedMember);
const fetchedMemberCol = await channel.members.fetch(true); const fetchedMemberCol = await channel.members.fetch(true);
assertType<Collection<Snowflake, ThreadMember>>(fetchedMemberCol); expectDeprecated(await channel.members.fetch(true));
expectType<Collection<Snowflake, ThreadMember>>(fetchedMemberCol);
} }
channel.setName('foo').then(updatedChannel => { channel.setName('foo').then(updatedChannel => {
@@ -528,21 +467,23 @@ client.on('guildCreate', async g => {
}); });
// @ts-expect-error no options // @ts-expect-error no options
assertIsPromiseMember(g.members.add(testUserId)); expectNotType<Promise<GuildMember>>(g.members.add(testUserId));
// @ts-expect-error no access token // @ts-expect-error no access token
assertIsPromiseMember(g.members.add(testUserId, {})); expectNotType<Promise<GuildMember>>(g.members.add(testUserId, {}));
// @ts-expect-error invalid role resolvable expectNotType<Promise<GuildMember>>(
assertIsPromiseMember(g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', roles: [g.roles.cache] })); // @ts-expect-error invalid role resolvable
g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', roles: [g.roles.cache] }),
);
assertType<Promise<GuildMember | null>>( expectType<Promise<GuildMember | null>>(
g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', fetchWhenExisting: false }), g.members.add(testUserId, { accessToken: 'totallyRealAccessToken', fetchWhenExisting: false }),
); );
assertIsPromiseMember(g.members.add(testUserId, { accessToken: 'totallyRealAccessToken' })); expectType<Promise<GuildMember>>(g.members.add(testUserId, { accessToken: 'totallyRealAccessToken' }));
assertIsPromiseMember( expectType<Promise<GuildMember>>(
g.members.add(testUserId, { g.members.add(testUserId, {
accessToken: 'totallyRealAccessToken', accessToken: 'totallyRealAccessToken',
mute: true, mute: true,
@@ -578,20 +519,18 @@ client.on('messageCreate', async message => {
assertIsMessage(channel.send({ embeds: [embed], files: [attachment] })); assertIsMessage(channel.send({ embeds: [embed], files: [attachment] }));
if (message.inGuild()) { if (message.inGuild()) {
assertType<Message<true>>(message); expectAssignable<Message<true>>(message);
const component = await message.awaitMessageComponent({ componentType: 'BUTTON' }); const component = await message.awaitMessageComponent({ componentType: 'BUTTON' });
assertType<ButtonInteraction<'cached'>>(component); expectType<ButtonInteraction<'cached'>>(component);
assertType<Message<true>>(await component.reply({ fetchReply: true })); expectType<Message<true>>(await component.reply({ fetchReply: true }));
const buttonCollector = message.createMessageComponentCollector({ componentType: 'BUTTON' }); const buttonCollector = message.createMessageComponentCollector({ componentType: 'BUTTON' });
assertType<InteractionCollector<ButtonInteraction<'cached'>>>(buttonCollector); expectType<InteractionCollector<ButtonInteraction<'cached'>>>(buttonCollector);
assertType<GuildTextBasedChannel>(message.channel); expectType<GuildTextBasedChannel>(message.channel);
} }
assertType<TextBasedChannels>(message.channel); expectType<TextBasedChannels>(message.channel);
expectNotType<GuildTextBasedChannel>(message.channel);
// @ts-expect-error
assertType<GuildTextBasedChannel>(message.channel);
// @ts-expect-error // @ts-expect-error
channel.send(); channel.send();
@@ -602,27 +541,27 @@ client.on('messageCreate', async message => {
// Verify that buttons interactions are inferred. // Verify that buttons interactions are inferred.
const buttonCollector = message.createMessageComponentCollector({ componentType: 'BUTTON' }); const buttonCollector = message.createMessageComponentCollector({ componentType: 'BUTTON' });
assertType<Promise<ButtonInteraction>>(message.awaitMessageComponent({ componentType: 'BUTTON' })); expectAssignable<Promise<ButtonInteraction>>(message.awaitMessageComponent({ componentType: 'BUTTON' }));
assertType<Promise<ButtonInteraction>>(channel.awaitMessageComponent({ componentType: 'BUTTON' })); expectAssignable<Promise<ButtonInteraction>>(channel.awaitMessageComponent({ componentType: 'BUTTON' }));
assertType<InteractionCollector<ButtonInteraction>>(buttonCollector); expectAssignable<InteractionCollector<ButtonInteraction>>(buttonCollector);
// Verify that select menus interaction are inferred. // Verify that select menus interaction are inferred.
const selectMenuCollector = message.createMessageComponentCollector({ componentType: 'SELECT_MENU' }); const selectMenuCollector = message.createMessageComponentCollector({ componentType: 'SELECT_MENU' });
assertType<Promise<SelectMenuInteraction>>(message.awaitMessageComponent({ componentType: 'SELECT_MENU' })); expectAssignable<Promise<SelectMenuInteraction>>(message.awaitMessageComponent({ componentType: 'SELECT_MENU' }));
assertType<Promise<SelectMenuInteraction>>(channel.awaitMessageComponent({ componentType: 'SELECT_MENU' })); expectAssignable<Promise<SelectMenuInteraction>>(channel.awaitMessageComponent({ componentType: 'SELECT_MENU' }));
assertType<InteractionCollector<SelectMenuInteraction>>(selectMenuCollector); expectAssignable<InteractionCollector<SelectMenuInteraction>>(selectMenuCollector);
// Verify that message component interactions are default collected types. // Verify that message component interactions are default collected types.
const defaultCollector = message.createMessageComponentCollector(); const defaultCollector = message.createMessageComponentCollector();
assertType<Promise<MessageComponentInteraction>>(message.awaitMessageComponent()); expectAssignable<Promise<MessageComponentInteraction>>(message.awaitMessageComponent());
assertType<Promise<MessageComponentInteraction>>(channel.awaitMessageComponent()); expectAssignable<Promise<MessageComponentInteraction>>(channel.awaitMessageComponent());
assertType<InteractionCollector<MessageComponentInteraction>>(defaultCollector); expectAssignable<InteractionCollector<MessageComponentInteraction>>(defaultCollector);
// Verify that additional options don't affect default collector types. // Verify that additional options don't affect default collector types.
const semiDefaultCollector = message.createMessageComponentCollector({ time: 10000 }); const semiDefaultCollector = message.createMessageComponentCollector({ time: 10000 });
assertType<InteractionCollector<MessageComponentInteraction>>(semiDefaultCollector); expectType<InteractionCollector<MessageComponentInteraction>>(semiDefaultCollector);
const semiDefaultCollectorChannel = message.createMessageComponentCollector({ time: 10000 }); const semiDefaultCollectorChannel = message.createMessageComponentCollector({ time: 10000 });
assertType<InteractionCollector<MessageComponentInteraction>>(semiDefaultCollectorChannel); expectType<InteractionCollector<MessageComponentInteraction>>(semiDefaultCollectorChannel);
// Verify that interaction collector options can't be used. // Verify that interaction collector options can't be used.
@@ -632,7 +571,7 @@ client.on('messageCreate', async message => {
// Make sure filter parameters are properly inferred. // Make sure filter parameters are properly inferred.
message.createMessageComponentCollector({ message.createMessageComponentCollector({
filter: i => { filter: i => {
assertType<MessageComponentInteraction>(i); expectType<MessageComponentInteraction>(i);
return true; return true;
}, },
}); });
@@ -640,7 +579,7 @@ client.on('messageCreate', async message => {
message.createMessageComponentCollector({ message.createMessageComponentCollector({
componentType: 'BUTTON', componentType: 'BUTTON',
filter: i => { filter: i => {
assertType<ButtonInteraction>(i); expectType<ButtonInteraction>(i);
return true; return true;
}, },
}); });
@@ -648,14 +587,14 @@ client.on('messageCreate', async message => {
message.createMessageComponentCollector({ message.createMessageComponentCollector({
componentType: 'SELECT_MENU', componentType: 'SELECT_MENU',
filter: i => { filter: i => {
assertType<SelectMenuInteraction>(i); expectType<SelectMenuInteraction>(i);
return true; return true;
}, },
}); });
message.awaitMessageComponent({ message.awaitMessageComponent({
filter: i => { filter: i => {
assertType<MessageComponentInteraction>(i); expectType<MessageComponentInteraction>(i);
return true; return true;
}, },
}); });
@@ -663,7 +602,7 @@ client.on('messageCreate', async message => {
message.awaitMessageComponent({ message.awaitMessageComponent({
componentType: 'BUTTON', componentType: 'BUTTON',
filter: i => { filter: i => {
assertType<ButtonInteraction>(i); expectType<ButtonInteraction>(i);
return true; return true;
}, },
}); });
@@ -671,7 +610,7 @@ client.on('messageCreate', async message => {
message.awaitMessageComponent({ message.awaitMessageComponent({
componentType: 'SELECT_MENU', componentType: 'SELECT_MENU',
filter: i => { filter: i => {
assertType<SelectMenuInteraction>(i); expectType<SelectMenuInteraction>(i);
return true; return true;
}, },
}); });
@@ -679,22 +618,19 @@ client.on('messageCreate', async message => {
const webhook = await message.fetchWebhook(); const webhook = await message.fetchWebhook();
if (webhook.isChannelFollower()) { if (webhook.isChannelFollower()) {
assertType<Guild | APIPartialGuild>(webhook.sourceGuild); expectAssignable<Guild | APIPartialGuild>(webhook.sourceGuild);
assertType<NewsChannel | APIPartialChannel>(webhook.sourceChannel); expectAssignable<NewsChannel | APIPartialChannel>(webhook.sourceChannel);
} else if (webhook.isIncoming()) { } else if (webhook.isIncoming()) {
assertType<string>(webhook.token); expectType<string>(webhook.token);
} }
// @ts-expect-error expectNotType<Guild | APIPartialGuild>(webhook.sourceGuild);
assertType<Guild | APIPartialGuild>(webhook.sourceGuild); expectNotType<NewsChannel | APIPartialChannel>(webhook.sourceChannel);
// @ts-expect-error expectNotType<string>(webhook.token);
assertType<NewsChannel | APIPartialChannel>(webhook.sourceChannel);
// @ts-expect-error
assertType<string>(webhook.token);
channel.awaitMessageComponent({ channel.awaitMessageComponent({
filter: i => { filter: i => {
assertType<MessageComponentInteraction>(i); expectType<MessageComponentInteraction>(i);
return true; return true;
}, },
}); });
@@ -702,7 +638,7 @@ client.on('messageCreate', async message => {
channel.awaitMessageComponent({ channel.awaitMessageComponent({
componentType: 'BUTTON', componentType: 'BUTTON',
filter: i => { filter: i => {
assertType<ButtonInteraction>(i); expectType<ButtonInteraction>(i);
return true; return true;
}, },
}); });
@@ -710,16 +646,16 @@ client.on('messageCreate', async message => {
channel.awaitMessageComponent({ channel.awaitMessageComponent({
componentType: 'SELECT_MENU', componentType: 'SELECT_MENU',
filter: i => { filter: i => {
assertType<SelectMenuInteraction>(i); expectType<SelectMenuInteraction>(i);
return true; return true;
}, },
}); });
}); });
client.on('interaction', async interaction => { client.on('interaction', async interaction => {
assertType<Snowflake | null>(interaction.guildId); expectType<Snowflake | null>(interaction.guildId);
assertType<Snowflake | null>(interaction.channelId); expectType<Snowflake | null>(interaction.channelId);
assertType<GuildMember | APIInteractionGuildMember | null>(interaction.member); expectType<GuildMember | APIInteractionGuildMember | null>(interaction.member);
if (!interaction.isCommand()) return; if (!interaction.isCommand()) return;
@@ -732,7 +668,7 @@ client.on('interaction', async interaction => {
await interaction.reply({ content: 'Hi!', components: [actionRow] }); await interaction.reply({ content: 'Hi!', components: [actionRow] });
// @ts-expect-error // @ts-expect-error
await interaction.reply({ content: 'Hi!', components: [[button]] }); interaction.reply({ content: 'Hi!', components: [[button]] });
// @ts-expect-error // @ts-expect-error
void new MessageActionRow({}); void new MessageActionRow({});
@@ -741,7 +677,7 @@ client.on('interaction', async interaction => {
await interaction.reply({ content: 'Hi!', components: [button] }); await interaction.reply({ content: 'Hi!', components: [button] });
if (interaction.isMessageComponent()) { if (interaction.isMessageComponent()) {
assertType<Snowflake>(interaction.channelId); expectType<Snowflake>(interaction.channelId);
} }
}); });
@@ -749,35 +685,30 @@ client.login('absolutely-valid-token');
// Test client conditional types // Test client conditional types
client.on('ready', client => { client.on('ready', client => {
assertType<Client<true>>(client); expectType<Client<true>>(client);
}); });
declare const loggedInClient: Client<true>; declare const loggedInClient: Client<true>;
assertType<ClientApplication>(loggedInClient.application); expectType<ClientApplication>(loggedInClient.application);
assertType<Date>(loggedInClient.readyAt); expectType<Date>(loggedInClient.readyAt);
assertType<number>(loggedInClient.readyTimestamp); expectType<number>(loggedInClient.readyTimestamp);
assertType<string>(loggedInClient.token); expectType<string>(loggedInClient.token);
assertType<number>(loggedInClient.uptime); expectType<number>(loggedInClient.uptime);
assertType<ClientUser>(loggedInClient.user); expectType<ClientUser>(loggedInClient.user);
declare const loggedOutClient: Client<false>; declare const loggedOutClient: Client<false>;
assertType<null>(loggedOutClient.application); expectType<null>(loggedOutClient.application);
assertType<null>(loggedOutClient.readyAt); expectType<null>(loggedOutClient.readyAt);
assertType<null>(loggedOutClient.readyTimestamp); expectType<null>(loggedOutClient.readyTimestamp);
assertType<string | null>(loggedOutClient.token); expectType<string | null>(loggedOutClient.token);
assertType<null>(loggedOutClient.uptime); expectType<null>(loggedOutClient.uptime);
assertType<null>(loggedOutClient.user); expectType<null>(loggedOutClient.user);
// Test type transformation: expectType<undefined>(serialize(undefined));
declare const assertType: <T>(value: T) => asserts value is T; expectType<null>(serialize(null));
declare const serialize: <T>(value: T) => Serialized<T>; expectType<number[]>(serialize([1, 2, 3]));
declare const notPropertyOf: <T, P extends PropertyKey>(value: T, property: P & Exclude<P, keyof T>) => void; expectType<{}>(serialize(new Set([1, 2, 3])));
expectType<{}>(
assertType<undefined>(serialize(undefined));
assertType<null>(serialize(null));
assertType<number[]>(serialize([1, 2, 3]));
assertType<{}>(serialize(new Set([1, 2, 3])));
assertType<{}>(
serialize( serialize(
new Map([ new Map([
[1, '2'], [1, '2'],
@@ -785,9 +716,9 @@ assertType<{}>(
]), ]),
), ),
); );
assertType<string>(serialize(new Permissions(Permissions.FLAGS.ATTACH_FILES))); expectType<string>(serialize(new Permissions(Permissions.FLAGS.ATTACH_FILES)));
assertType<number>(serialize(new Intents(Intents.FLAGS.GUILDS))); expectType<number>(serialize(new Intents(Intents.FLAGS.GUILDS)));
assertType<unknown>( expectAssignable<unknown>(
serialize( serialize(
new Collection([ new Collection([
[1, '2'], [1, '2'],
@@ -795,18 +726,18 @@ assertType<unknown>(
]), ]),
), ),
); );
assertType<never>(serialize(Symbol('a'))); expectType<never>(serialize(Symbol('a')));
assertType<never>(serialize(() => {})); expectType<never>(serialize(() => {}));
assertType<never>(serialize(BigInt(42))); expectType<never>(serialize(BigInt(42)));
// Test type return of broadcastEval: // Test type return of broadcastEval:
declare const shardClientUtil: ShardClientUtil; declare const shardClientUtil: ShardClientUtil;
declare const shardingManager: ShardingManager; declare const shardingManager: ShardingManager;
assertType<Promise<number[]>>(shardingManager.broadcastEval(() => 1)); expectType<Promise<number[]>>(shardingManager.broadcastEval(() => 1));
assertType<Promise<number[]>>(shardClientUtil.broadcastEval(() => 1)); expectType<Promise<number[]>>(shardClientUtil.broadcastEval(() => 1));
assertType<Promise<number[]>>(shardingManager.broadcastEval(async () => 1)); expectType<Promise<number[]>>(shardingManager.broadcastEval(async () => 1));
assertType<Promise<number[]>>(shardClientUtil.broadcastEval(async () => 1)); expectType<Promise<number[]>>(shardClientUtil.broadcastEval(async () => 1));
declare const dmChannel: DMChannel; declare const dmChannel: DMChannel;
declare const threadChannel: ThreadChannel; declare const threadChannel: ThreadChannel;
@@ -816,17 +747,17 @@ declare const user: User;
declare const guildMember: GuildMember; declare const guildMember: GuildMember;
// Test whether the structures implement send // Test whether the structures implement send
assertType<TextBasedChannelFields['send']>(dmChannel.send); expectType<TextBasedChannelFields['send']>(dmChannel.send);
assertType<TextBasedChannelFields>(threadChannel); expectType<ThreadChannel>(threadChannel);
assertType<TextBasedChannelFields>(newsChannel); expectType<NewsChannel>(newsChannel);
assertType<TextBasedChannelFields>(textChannel); expectType<TextChannel>(textChannel);
assertType<PartialTextBasedChannelFields>(user); expectAssignable<PartialTextBasedChannelFields>(user);
assertType<PartialTextBasedChannelFields>(guildMember); expectAssignable<PartialTextBasedChannelFields>(guildMember);
assertType<Message | null>(dmChannel.lastMessage); expectType<Message | null>(dmChannel.lastMessage);
assertType<Message | null>(threadChannel.lastMessage); expectType<Message | null>(threadChannel.lastMessage);
assertType<Message | null>(newsChannel.lastMessage); expectType<Message | null>(newsChannel.lastMessage);
assertType<Message | null>(textChannel.lastMessage); expectType<Message | null>(textChannel.lastMessage);
notPropertyOf(user, 'lastMessage'); notPropertyOf(user, 'lastMessage');
notPropertyOf(user, 'lastMessageId'); notPropertyOf(user, 'lastMessageId');
@@ -836,21 +767,21 @@ notPropertyOf(guildMember, 'lastMessageId');
// Test collector event parameters // Test collector event parameters
declare const messageCollector: MessageCollector; declare const messageCollector: MessageCollector;
messageCollector.on('collect', (...args) => { messageCollector.on('collect', (...args) => {
assertType<[Message]>(args); expectType<[Message]>(args);
}); });
declare const reactionCollector: ReactionCollector; declare const reactionCollector: ReactionCollector;
reactionCollector.on('dispose', (...args) => { reactionCollector.on('dispose', (...args) => {
assertType<[MessageReaction, User]>(args); expectType<[MessageReaction, User]>(args);
}); });
// Make sure the properties are typed correctly, and that no backwards properties // Make sure the properties are typed correctly, and that no backwards properties
// (K -> V and V -> K) exist: // (K -> V and V -> K) exist:
assertType<'messageCreate'>(Constants.Events.MESSAGE_CREATE); expectType<'messageCreate'>(Constants.Events.MESSAGE_CREATE);
assertType<'close'>(Constants.ShardEvents.CLOSE); expectType<'close'>(Constants.ShardEvents.CLOSE);
assertType<1>(Constants.Status.CONNECTING); expectType<1>(Constants.Status.CONNECTING);
assertType<0>(Constants.Opcodes.DISPATCH); expectType<0>(Constants.Opcodes.DISPATCH);
assertType<2>(Constants.ClientApplicationAssetTypes.BIG); expectType<2>(Constants.ClientApplicationAssetTypes.BIG);
declare const applicationCommandData: ApplicationCommandData; declare const applicationCommandData: ApplicationCommandData;
declare const applicationCommandResolvable: ApplicationCommandResolvable; declare const applicationCommandResolvable: ApplicationCommandResolvable;
@@ -858,19 +789,18 @@ declare const applicationCommandManager: ApplicationCommandManager;
{ {
type ApplicationCommandScope = ApplicationCommand<{ guild: GuildResolvable }>; type ApplicationCommandScope = ApplicationCommand<{ guild: GuildResolvable }>;
assertType<Promise<ApplicationCommandScope>>(applicationCommandManager.create(applicationCommandData)); expectType<Promise<ApplicationCommandScope>>(applicationCommandManager.create(applicationCommandData));
assertType<Promise<ApplicationCommandScope>>(applicationCommandManager.create(applicationCommandData, '0')); expectAssignable<Promise<ApplicationCommand>>(applicationCommandManager.create(applicationCommandData, '0'));
assertType<Promise<ApplicationCommandScope>>(applicationCommandManager.create(applicationCommandData, undefined)); expectType<Promise<ApplicationCommandScope>>(
assertType<Promise<ApplicationCommandScope>>(
applicationCommandManager.edit(applicationCommandResolvable, applicationCommandData), applicationCommandManager.edit(applicationCommandResolvable, applicationCommandData),
); );
assertType<Promise<ApplicationCommand>>( expectType<Promise<ApplicationCommand>>(
applicationCommandManager.edit(applicationCommandResolvable, applicationCommandData, '0'), applicationCommandManager.edit(applicationCommandResolvable, applicationCommandData, '0'),
); );
assertType<Promise<Collection<Snowflake, ApplicationCommandScope>>>( expectType<Promise<Collection<Snowflake, ApplicationCommandScope>>>(
applicationCommandManager.set([applicationCommandData]), applicationCommandManager.set([applicationCommandData]),
); );
assertType<Promise<Collection<Snowflake, ApplicationCommand>>>( expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(
applicationCommandManager.set([applicationCommandData], '0'), applicationCommandManager.set([applicationCommandData], '0'),
); );
} }
@@ -887,272 +817,248 @@ declare const applicationNonChoiceOptionData: ApplicationCommandOptionData & {
declare const applicationSubGroupCommandData: ApplicationCommandSubGroupData; declare const applicationSubGroupCommandData: ApplicationCommandSubGroupData;
{ {
assertType<'SUB_COMMAND_GROUP' | ApplicationCommandOptionTypes.SUB_COMMAND_GROUP>( expectType<'SUB_COMMAND_GROUP' | ApplicationCommandOptionTypes.SUB_COMMAND_GROUP>(
applicationSubGroupCommandData.type, applicationSubGroupCommandData.type,
); );
assertType<ApplicationCommandSubCommandData[] | undefined>(applicationSubGroupCommandData.options); expectType<ApplicationCommandSubCommandData[] | undefined>(applicationSubGroupCommandData.options);
}
declare const applicationSubCommandData: ApplicationCommandSubCommandData;
{
assertType<'SUB_COMMAND' | ApplicationCommandOptionTypes.SUB_COMMAND>(applicationSubCommandData.type);
// Check that only subcommands can have no subcommand or subcommand group sub-options.
assertType<
| (
| ApplicationCommandChoicesData
| ApplicationCommandNonOptionsData
| ApplicationCommandChannelOptionData
| ApplicationCommandAutocompleteOption
| ApplicationCommandNumericOptionData
)[]
| undefined
>(applicationSubCommandData.options);
} }
declare const guildApplicationCommandManager: GuildApplicationCommandManager; declare const guildApplicationCommandManager: GuildApplicationCommandManager;
assertType<Promise<Collection<Snowflake, ApplicationCommand>>>(guildApplicationCommandManager.fetch()); expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(guildApplicationCommandManager.fetch());
assertType<Promise<Collection<Snowflake, ApplicationCommand>>>(guildApplicationCommandManager.fetch(undefined, {})); expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(guildApplicationCommandManager.fetch(undefined, {}));
assertType<Promise<ApplicationCommand>>(guildApplicationCommandManager.fetch('0')); expectType<Promise<ApplicationCommand>>(guildApplicationCommandManager.fetch('0'));
declare const guildChannelManager: GuildChannelManager; declare const guildChannelManager: GuildChannelManager;
{ {
type AnyChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel | StoreChannel | StageChannel; type AnyChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel | StoreChannel | StageChannel;
assertType<Promise<VoiceChannel>>(guildChannelManager.create('name', { type: 'GUILD_VOICE' })); expectType<Promise<VoiceChannel>>(guildChannelManager.create('name', { type: 'GUILD_VOICE' }));
assertType<Promise<CategoryChannel>>(guildChannelManager.create('name', { type: 'GUILD_CATEGORY' })); expectType<Promise<CategoryChannel>>(guildChannelManager.create('name', { type: 'GUILD_CATEGORY' }));
assertType<Promise<TextChannel>>(guildChannelManager.create('name', { type: 'GUILD_TEXT' })); expectType<Promise<TextChannel>>(guildChannelManager.create('name', { type: 'GUILD_TEXT' }));
assertType<Promise<NewsChannel>>(guildChannelManager.create('name', { type: 'GUILD_NEWS' })); expectType<Promise<NewsChannel>>(guildChannelManager.create('name', { type: 'GUILD_NEWS' }));
assertType<Promise<StoreChannel>>(guildChannelManager.create('name', { type: 'GUILD_STORE' })); expectType<Promise<StoreChannel>>(guildChannelManager.create('name', { type: 'GUILD_STORE' }));
assertType<Promise<StageChannel>>(guildChannelManager.create('name', { type: 'GUILD_STAGE_VOICE' })); expectType<Promise<StageChannel>>(guildChannelManager.create('name', { type: 'GUILD_STAGE_VOICE' }));
assertType<Promise<Collection<Snowflake, AnyChannel>>>(guildChannelManager.fetch()); expectType<Promise<Collection<Snowflake, AnyChannel>>>(guildChannelManager.fetch());
assertType<Promise<Collection<Snowflake, AnyChannel>>>(guildChannelManager.fetch(undefined, {})); expectType<Promise<Collection<Snowflake, AnyChannel>>>(guildChannelManager.fetch(undefined, {}));
assertType<Promise<AnyChannel | null>>(guildChannelManager.fetch('0')); expectType<Promise<AnyChannel | null>>(guildChannelManager.fetch('0'));
} }
declare const roleManager: RoleManager; declare const roleManager: RoleManager;
assertType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch()); expectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch());
assertType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch(undefined, {})); expectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch(undefined, {}));
assertType<Promise<Role | null>>(roleManager.fetch('0')); expectType<Promise<Role | null>>(roleManager.fetch('0'));
declare const guildEmojiManager: GuildEmojiManager; declare const guildEmojiManager: GuildEmojiManager;
assertType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch()); expectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch());
assertType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch(undefined, {})); expectType<Promise<Collection<Snowflake, GuildEmoji>>>(guildEmojiManager.fetch(undefined, {}));
assertType<Promise<GuildEmoji | null>>(guildEmojiManager.fetch('0')); expectType<Promise<GuildEmoji>>(guildEmojiManager.fetch('0'));
declare const typing: Typing; declare const typing: Typing;
assertType<PartialUser>(typing.user); expectType<PartialUser>(typing.user);
if (typing.user.partial) assertType<null>(typing.user.username); if (typing.user.partial) expectType<null>(typing.user.username);
assertType<TextBasedChannels>(typing.channel); expectType<TextBasedChannels>(typing.channel);
if (typing.channel.partial) assertType<undefined>(typing.channel.lastMessageId); if (typing.channel.partial) expectType<undefined>(typing.channel.lastMessageId);
assertType<GuildMember | null>(typing.member); expectType<GuildMember | null>(typing.member);
assertType<Guild | null>(typing.guild); expectType<Guild | null>(typing.guild);
if (typing.inGuild()) { if (typing.inGuild()) {
assertType<Guild>(typing.channel.guild); expectType<Guild>(typing.channel.guild);
assertType<Guild>(typing.guild); expectType<Guild>(typing.guild);
} }
// Test partials structures // Test partials structures
client.on('guildMemberRemove', member => { client.on('guildMemberRemove', member => {
if (member.partial) return assertType<null>(member.joinedAt); if (member.partial) return expectType<null>(member.joinedAt);
assertType<Date | null>(member.joinedAt); expectType<Date | null>(member.joinedAt);
}); });
client.on('messageReactionAdd', async reaction => { client.on('messageReactionAdd', async reaction => {
if (reaction.partial) { if (reaction.partial) {
assertType<null>(reaction.count); expectType<null>(reaction.count);
reaction = await reaction.fetch(); reaction = await reaction.fetch();
} }
assertType<number>(reaction.count); expectType<number>(reaction.count);
if (reaction.message.partial) return assertType<string | null>(reaction.message.content); if (reaction.message.partial) return expectType<string | null>(reaction.message.content);
assertType<string>(reaction.message.content); expectType<string>(reaction.message.content);
}); });
// Test interactions // Test interactions
declare const interaction: Interaction; declare const interaction: Interaction;
declare const booleanValue: boolean; declare const booleanValue: boolean;
if (interaction.inGuild()) assertType<Snowflake>(interaction.guildId); if (interaction.inGuild()) expectType<Snowflake>(interaction.guildId);
client.on('interactionCreate', async interaction => { client.on('interactionCreate', async interaction => {
assertType<Snowflake | null>(interaction.guildId);
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<GuildMember>(interaction.member); expectAssignable<GuildMember>(interaction.member);
// @ts-expect-error expectNotType<CommandInteraction<'cached'>>(interaction);
assertType<CommandInteraction<'cached'>>(interaction); expectAssignable<Interaction>(interaction);
assertType<Interaction>(interaction);
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<APIInteractionGuildMember>(interaction.member); expectAssignable<APIInteractionGuildMember>(interaction.member);
// @ts-expect-error expectNotAssignable<Interaction<'cached'>>(interaction);
consumeCachedInteraction(interaction);
} else { } else {
assertType<APIGuildMember | GuildMember | null>(interaction.member); expectType<APIInteractionGuildMember | GuildMember | null>(interaction.member);
// @ts-expect-error expectNotAssignable<Interaction<'cached'>>(interaction);
consumeCachedInteraction(interaction);
} }
if (interaction.isContextMenu()) { if (interaction.isContextMenu()) {
assertType<ContextMenuInteraction>(interaction); expectType<ContextMenuInteraction>(interaction);
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<ContextMenuInteraction>(interaction); expectAssignable<ContextMenuInteraction>(interaction);
assertType<Guild>(interaction.guild); expectAssignable<Guild>(interaction.guild);
assertType<BaseCommandInteraction<'cached'>>(interaction); expectAssignable<BaseCommandInteraction<'cached'>>(interaction);
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<ContextMenuInteraction>(interaction); expectAssignable<ContextMenuInteraction>(interaction);
assertType<null>(interaction.guild); expectType<null>(interaction.guild);
} else if (interaction.inGuild()) { } else if (interaction.inGuild()) {
assertType<ContextMenuInteraction>(interaction); expectAssignable<ContextMenuInteraction>(interaction);
assertType<Guild | null>(interaction.guild); expectType<Guild | null>(interaction.guild);
} }
} }
if (interaction.isButton()) { if (interaction.isButton()) {
assertType<ButtonInteraction>(interaction); expectType<ButtonInteraction>(interaction);
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<ButtonInteraction>(interaction); expectAssignable<ButtonInteraction>(interaction);
assertType<Guild>(interaction.guild); expectType<Guild>(interaction.guild);
assertType<Promise<Message>>(interaction.reply({ fetchReply: true })); expectAssignable<Promise<Message>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<ButtonInteraction>(interaction); expectAssignable<ButtonInteraction>(interaction);
assertType<null>(interaction.guild); expectType<null>(interaction.guild);
assertType<Promise<APIMessage>>(interaction.reply({ fetchReply: true })); expectType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inGuild()) { } else if (interaction.inGuild()) {
assertType<ButtonInteraction>(interaction); expectAssignable<ButtonInteraction>(interaction);
assertType<Guild | null>(interaction.guild); expectAssignable<Guild | null>(interaction.guild);
assertType<Promise<APIMessage | Message>>(interaction.reply({ fetchReply: true })); expectType<Promise<APIMessage | Message>>(interaction.reply({ fetchReply: true }));
} }
} }
if (interaction.isMessageComponent()) { if (interaction.isMessageComponent()) {
assertType<MessageComponentInteraction>(interaction); expectType<MessageComponentInteraction>(interaction);
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<MessageComponentInteraction>(interaction); expectAssignable<MessageComponentInteraction>(interaction);
assertType<Guild>(interaction.guild); expectType<Guild>(interaction.guild);
assertType<Promise<Message>>(interaction.reply({ fetchReply: true })); expectAssignable<Promise<Message>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<MessageComponentInteraction>(interaction); expectAssignable<MessageComponentInteraction>(interaction);
assertType<null>(interaction.guild); expectType<null>(interaction.guild);
assertType<Promise<APIMessage>>(interaction.reply({ fetchReply: true })); expectType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inGuild()) { } else if (interaction.inGuild()) {
assertType<MessageComponentInteraction>(interaction); expectAssignable<MessageComponentInteraction>(interaction);
assertType<Guild | null>(interaction.guild); expectType<Guild | null>(interaction.guild);
assertType<Promise<APIMessage | Message>>(interaction.reply({ fetchReply: true })); expectType<Promise<APIMessage | Message>>(interaction.reply({ fetchReply: true }));
} }
} }
if (interaction.isSelectMenu()) { if (interaction.isSelectMenu()) {
assertType<SelectMenuInteraction>(interaction); expectType<SelectMenuInteraction>(interaction);
if (interaction.inCachedGuild()) { if (interaction.inCachedGuild()) {
assertType<SelectMenuInteraction>(interaction); expectAssignable<SelectMenuInteraction>(interaction);
assertType<Guild>(interaction.guild); expectType<Guild>(interaction.guild);
assertType<Promise<Message>>(interaction.reply({ fetchReply: true })); expectType<Promise<Message<true>>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inRawGuild()) { } else if (interaction.inRawGuild()) {
assertType<SelectMenuInteraction>(interaction); expectAssignable<SelectMenuInteraction>(interaction);
assertType<null>(interaction.guild); expectType<null>(interaction.guild);
assertType<Promise<APIMessage>>(interaction.reply({ fetchReply: true })); expectType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
} else if (interaction.inGuild()) { } else if (interaction.inGuild()) {
assertType<SelectMenuInteraction>(interaction); expectAssignable<SelectMenuInteraction>(interaction);
assertType<Guild | null>(interaction.guild); expectType<Guild | null>(interaction.guild);
assertType<Promise<Message | APIMessage>>(interaction.reply({ fetchReply: true })); expectType<Promise<Message | APIMessage>>(interaction.reply({ fetchReply: true }));
} }
} }
if (interaction.isCommand()) { if (interaction.isCommand()) {
if (interaction.inRawGuild()) { if (interaction.inRawGuild()) {
// @ts-expect-error expectNotAssignable<Interaction<'cached'>>(interaction);
consumeCachedCommand(interaction); expectAssignable<CommandInteraction>(interaction);
assertType<CommandInteraction>(interaction); expectType<Promise<APIMessage>>(interaction.reply({ fetchReply: true }));
assertType<Promise<APIMessage>>(interaction.reply({ fetchReply: true })); expectType<APIInteractionDataResolvedGuildMember | null>(interaction.options.getMember('test'));
assertType<APIInteractionDataResolvedGuildMember | null>(interaction.options.getMember('test')); expectType<APIInteractionDataResolvedGuildMember>(interaction.options.getMember('test', true));
assertType<APIInteractionDataResolvedGuildMember>(interaction.options.getMember('test', true));
assertType<APIInteractionDataResolvedChannel>(interaction.options.getChannel('test', true)); expectType<APIInteractionDataResolvedChannel>(interaction.options.getChannel('test', true));
assertType<APIRole>(interaction.options.getRole('test', true)); expectType<APIRole>(interaction.options.getRole('test', true));
} else if (interaction.inCachedGuild()) { } else if (interaction.inCachedGuild()) {
const msg = await interaction.reply({ fetchReply: true }); const msg = await interaction.reply({ fetchReply: true });
const btn = await msg.awaitMessageComponent({ componentType: 'BUTTON' }); const btn = await msg.awaitMessageComponent({ componentType: 'BUTTON' });
assertType<Message>(msg); expectType<Message<true>>(msg);
assertType<ButtonInteraction<'cached'>>(btn); expectType<ButtonInteraction<'cached'>>(btn);
assertType<CommandInteraction<'cached'>>(interaction); expectType<GuildMember | null>(interaction.options.getMember('test'));
assertType<GuildMember>(interaction.options.getMember('test', true)); expectAssignable<CommandInteraction>(interaction);
assertType<GuildMember | null>(interaction.options.getMember('test')); expectType<Promise<Message<true>>>(interaction.reply({ fetchReply: true }));
assertType<CommandInteraction>(interaction);
assertType<Promise<Message>>(interaction.reply({ fetchReply: true }));
assertType<GuildChannel | ThreadChannel>(interaction.options.getChannel('test', true)); expectType<GuildChannel | ThreadChannel>(interaction.options.getChannel('test', true));
assertType<Role>(interaction.options.getRole('test', true)); expectType<Role>(interaction.options.getRole('test', true));
} else { } else {
// @ts-expect-error // @ts-expect-error
consumeCachedCommand(interaction); consumeCachedCommand(interaction);
assertType<CommandInteraction>(interaction); expectType<CommandInteraction>(interaction);
assertType<Promise<Message | APIMessage>>(interaction.reply({ fetchReply: true })); expectType<Promise<Message | APIMessage>>(interaction.reply({ fetchReply: true }));
assertType<APIInteractionDataResolvedGuildMember | GuildMember | null>(interaction.options.getMember('test')); expectType<APIInteractionDataResolvedGuildMember | GuildMember | null>(interaction.options.getMember('test'));
assertType<APIInteractionDataResolvedGuildMember | GuildMember>(interaction.options.getMember('test', true)); expectType<APIInteractionDataResolvedGuildMember | GuildMember>(interaction.options.getMember('test', true));
assertType<GuildChannel | ThreadChannel | APIInteractionDataResolvedChannel>( expectType<GuildChannel | ThreadChannel | APIInteractionDataResolvedChannel>(
interaction.options.getChannel('test', true), interaction.options.getChannel('test', true),
); );
assertType<APIRole | Role>(interaction.options.getRole('test', true)); expectType<APIRole | Role>(interaction.options.getRole('test', true));
} }
assertType<CommandInteraction>(interaction); expectType<CommandInteraction>(interaction);
assertType<Omit<CommandInteractionOptionResolver<CacheType>, 'getFocused' | 'getMessage'>>(interaction.options); expectType<Omit<CommandInteractionOptionResolver<CacheType>, 'getFocused' | 'getMessage'>>(interaction.options);
assertType<readonly CommandInteractionOption[]>(interaction.options.data); expectType<readonly CommandInteractionOption[]>(interaction.options.data);
const optionalOption = interaction.options.get('name'); const optionalOption = interaction.options.get('name');
const requiredOption = interaction.options.get('name', true); const requiredOption = interaction.options.get('name', true);
assertType<CommandInteractionOption | null>(optionalOption); expectType<CommandInteractionOption | null>(optionalOption);
assertType<CommandInteractionOption>(requiredOption); expectType<CommandInteractionOption>(requiredOption);
assertType<CommandInteractionOption[] | undefined>(requiredOption.options); expectType<CommandInteractionOption[] | undefined>(requiredOption.options);
assertType<string | null>(interaction.options.getString('name', booleanValue)); expectType<string | null>(interaction.options.getString('name', booleanValue));
assertType<string | null>(interaction.options.getString('name', false)); expectType<string | null>(interaction.options.getString('name', false));
assertType<string>(interaction.options.getString('name', true)); expectType<string>(interaction.options.getString('name', true));
assertType<string>(interaction.options.getSubcommand()); expectType<string>(interaction.options.getSubcommand());
assertType<string>(interaction.options.getSubcommand(true)); expectType<string>(interaction.options.getSubcommand(true));
assertType<string | null>(interaction.options.getSubcommand(booleanValue)); expectType<string | null>(interaction.options.getSubcommand(booleanValue));
assertType<string | null>(interaction.options.getSubcommand(false)); expectType<string | null>(interaction.options.getSubcommand(false));
assertType<string>(interaction.options.getSubcommandGroup()); expectType<string>(interaction.options.getSubcommandGroup());
assertType<string>(interaction.options.getSubcommandGroup(true)); expectType<string>(interaction.options.getSubcommandGroup(true));
assertType<string | null>(interaction.options.getSubcommandGroup(booleanValue)); expectType<string | null>(interaction.options.getSubcommandGroup(booleanValue));
assertType<string | null>(interaction.options.getSubcommandGroup(false)); expectType<string | null>(interaction.options.getSubcommandGroup(false));
} }
}); });
declare const shard: Shard; declare const shard: Shard;
shard.on('death', process => { shard.on('death', process => {
assertType<ChildProcess>(process); expectType<ChildProcess>(process);
}); });
declare const webSocketShard: WebSocketShard; declare const webSocketShard: WebSocketShard;
webSocketShard.on('close', event => { webSocketShard.on('close', event => {
assertType<CloseEvent>(event); expectType<CloseEvent>(event);
}); });
declare const collector: Collector<string, Interaction, string[]>; declare const collector: Collector<string, Interaction, string[]>;
collector.on('collect', (collected, ...other) => { collector.on('collect', (collected, ...other) => {
assertType<Interaction>(collected); expectType<Interaction>(collected);
assertType<string[]>(other); expectType<string[]>(other);
}); });
collector.on('dispose', (vals, ...other) => { collector.on('dispose', (vals, ...other) => {
assertType<Interaction>(vals); expectType<Interaction>(vals);
assertType<string[]>(other); expectType<string[]>(other);
}); });
collector.on('end', (collection, reason) => { collector.on('end', (collection, reason) => {
assertType<Collection<string, Interaction>>(collection); expectType<Collection<string, Interaction>>(collection);
assertType<string>(reason); expectType<string>(reason);
}); });
assertType<Promise<number | null>>(shard.eval(c => c.readyTimestamp)); expectType<Promise<number | null>>(shard.eval(c => c.readyTimestamp));