Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Sharding): strict type context and return #5933

Merged
merged 2 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 29 additions & 11 deletions typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ declare enum WebhookTypes {
'Channel Follower' = 2,
}

type Awaited<T> = T | Promise<T>;
type Awaited<T> = T | PromiseLike<T>;

declare module 'discord.js' {
import BaseCollection from '@discordjs/collection';
Expand Down Expand Up @@ -1756,13 +1756,16 @@ declare module 'discord.js' {
public readonly ids: number[];
public mode: ShardingManagerMode;
public parentPort: any | null;
public broadcastEval<T>(fn: (client: Client) => T): Promise<T[]>;
public broadcastEval<T>(fn: (client: Client) => T, options: { shard: number }): Promise<T>;
public broadcastEval<T, P>(fn: (client: Client, context: P) => T, options: { context: P }): Promise<T[]>;
public broadcastEval<T>(fn: (client: Client) => Awaited<T>): Promise<Serialized<T>[]>;
public broadcastEval<T>(fn: (client: Client) => Awaited<T>, options: { shard: number }): Promise<Serialized<T>>;
public broadcastEval<T, P>(
fn: (client: Client, context: P) => T,
fn: (client: Client, context: Serialized<P>) => Awaited<T>,
options: { context: P },
): Promise<Serialized<T>[]>;
public broadcastEval<T, P>(
fn: (client: Client, context: Serialized<P>) => Awaited<T>,
options: { context: P; shard: number },
): Promise<T>;
): Promise<Serialized<T>>;
public fetchClientValues(prop: string): Promise<any[]>;
public fetchClientValues(prop: string, shard: number): Promise<any>;
public respawnAll(options?: MultipleShardRespawnOptions): Promise<void>;
Expand All @@ -1785,13 +1788,16 @@ declare module 'discord.js' {
public totalShards: number | 'auto';
public shardList: number[] | 'auto';
public broadcast(message: any): Promise<Shard[]>;
public broadcastEval<T>(fn: (client: Client) => T): Promise<T[]>;
public broadcastEval<T>(fn: (client: Client) => T, options: { shard: number }): Promise<T>;
public broadcastEval<T, P>(fn: (client: Client, context: P) => T, options: { context: P }): Promise<T[]>;
public broadcastEval<T>(fn: (client: Client) => Awaited<T>): Promise<Serialized<T>[]>;
public broadcastEval<T>(fn: (client: Client) => Awaited<T>, options: { shard: number }): Promise<Serialized<T>>;
public broadcastEval<T, P>(
fn: (client: Client, context: Serialized<P>) => Awaited<T>,
options: { context: P },
): Promise<Serialized<T>[]>;
public broadcastEval<T, P>(
fn: (client: Client, context: P) => T,
fn: (client: Client, context: Serialized<P>) => Awaited<T>,
options: { context: P; shard: number },
): Promise<T>;
): Promise<Serialized<T>>;
public createShard(id: number): Shard;
public fetchClientValues(prop: string): Promise<any[]>;
public fetchClientValues(prop: string, shard: number): Promise<any>;
Expand Down Expand Up @@ -4321,5 +4327,17 @@ declare module 'discord.js' {
| 'STAGE_INSTANCE_UPDATE'
| 'STAGE_INSTANCE_DELETE';

type Serialized<T> = T extends symbol | bigint | (() => unknown)
? never
: T extends number | string | boolean | undefined
? T
: T extends { toJSON(): infer R }
? R
: T extends ReadonlyArray<infer V>
? Serialized<V>[]
: T extends ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
? {}
: { [K in keyof T]: Serialized<T[K]> };

//#endregion
}
52 changes: 51 additions & 1 deletion typings/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
/// <reference path="index.d.ts" />

import { Client, Intents, Message, MessageAttachment, MessageEmbed } from 'discord.js';
import {
Client,
Collection,
Intents,
Message,
MessageAttachment,
MessageEmbed,
Permissions,
Serialized,
ShardClientUtil,
ShardingManager,
} from 'discord.js';

const client: Client = new Client({
intents: Intents.NON_PRIVILEGED,
Expand Down Expand Up @@ -48,3 +59,42 @@ client.on('message', ({ channel }) => {
});

client.login('absolutely-valid-token');

// Test type transformation:
declare const assertType: <T>(value: T) => asserts value is T;
declare const serialize: <T>(value: T) => Serialized<T>;

assertType<undefined>(serialize(undefined));
assertType<null>(serialize(null));
assertType<number[]>(serialize([1, 2, 3]));
assertType<{}>(serialize(new Set([1, 2, 3])));
assertType<{}>(
serialize(
new Map([
[1, '2'],
[2, '4'],
]),
),
);
assertType<string>(serialize(new Permissions(Permissions.FLAGS.ATTACH_FILES)));
assertType<number>(serialize(new Intents(Intents.FLAGS.GUILDS)));
assertType<unknown>(
serialize(
new Collection([
[1, '2'],
[2, '4'],
]),
),
);
assertType<never>(serialize(Symbol('a')));
assertType<never>(serialize(() => {}));
assertType<never>(serialize(BigInt(42)));

// Test type return of broadcastEval:
declare const shardClientUtil: ShardClientUtil;
declare const shardingManager: ShardingManager;

assertType<Promise<number[]>>(shardingManager.broadcastEval(() => 1));
assertType<Promise<number[]>>(shardClientUtil.broadcastEval(() => 1));
assertType<Promise<number[]>>(shardingManager.broadcastEval(async () => 1));
assertType<Promise<number[]>>(shardClientUtil.broadcastEval(async () => 1));