From 306cc90e83746ce14ad82e8221b02d7f9a5cdb87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Rom=C3=A1n?= Date: Sat, 26 Jun 2021 23:56:48 +0200 Subject: [PATCH 1/2] fix(Sharding): strict type context and return --- typings/index.d.ts | 38 ++++++++++++++++++++++++++++---------- typings/index.ts | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index c3083c54daa4..8b9f5cc36275 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1756,13 +1756,16 @@ declare module 'discord.js' { public readonly ids: number[]; public mode: ShardingManagerMode; public parentPort: any | null; - public broadcastEval(fn: (client: Client) => T): Promise; - public broadcastEval(fn: (client: Client) => T, options: { shard: number }): Promise; - public broadcastEval(fn: (client: Client, context: P) => T, options: { context: P }): Promise; + public broadcastEval(fn: (client: Client) => T): Promise[]>; + public broadcastEval(fn: (client: Client) => T, options: { shard: number }): Promise>; public broadcastEval( - fn: (client: Client, context: P) => T, + fn: (client: Client, context: Serialized

) => T, + options: { context: P }, + ): Promise[]>; + public broadcastEval( + fn: (client: Client, context: Serialized

) => T, options: { context: P; shard: number }, - ): Promise; + ): Promise>; public fetchClientValues(prop: string): Promise; public fetchClientValues(prop: string, shard: number): Promise; public respawnAll(options?: MultipleShardRespawnOptions): Promise; @@ -1785,13 +1788,16 @@ declare module 'discord.js' { public totalShards: number | 'auto'; public shardList: number[] | 'auto'; public broadcast(message: any): Promise; - public broadcastEval(fn: (client: Client) => T): Promise; - public broadcastEval(fn: (client: Client) => T, options: { shard: number }): Promise; - public broadcastEval(fn: (client: Client, context: P) => T, options: { context: P }): Promise; + public broadcastEval(fn: (client: Client) => T): Promise[]>; + public broadcastEval(fn: (client: Client) => T, options: { shard: number }): Promise>; + public broadcastEval( + fn: (client: Client, context: Serialized

) => T, + options: { context: P }, + ): Promise[]>; public broadcastEval( - fn: (client: Client, context: P) => T, + fn: (client: Client, context: Serialized

) => T, options: { context: P; shard: number }, - ): Promise; + ): Promise>; public createShard(id: number): Shard; public fetchClientValues(prop: string): Promise; public fetchClientValues(prop: string, shard: number): Promise; @@ -4321,5 +4327,17 @@ declare module 'discord.js' { | 'STAGE_INSTANCE_UPDATE' | 'STAGE_INSTANCE_DELETE'; + type Serialized = T extends symbol | bigint | (() => unknown) + ? never + : T extends number | string | boolean | undefined + ? T + : T extends { toJSON(): infer R } + ? R + : T extends ReadonlyArray + ? Serialized[] + : T extends ReadonlyMap | ReadonlySet + ? {} + : { [K in keyof T]: Serialized }; + //#endregion } diff --git a/typings/index.ts b/typings/index.ts index 788f17adc1be..a3c5f16113e5 100644 --- a/typings/index.ts +++ b/typings/index.ts @@ -1,6 +1,15 @@ /// -import { Client, Intents, Message, MessageAttachment, MessageEmbed } from 'discord.js'; +import { + Client, + Collection, + Intents, + Message, + MessageAttachment, + MessageEmbed, + Permissions, + Serialized, +} from 'discord.js'; const client: Client = new Client({ intents: Intents.NON_PRIVILEGED, @@ -48,3 +57,32 @@ client.on('message', ({ channel }) => { }); client.login('absolutely-valid-token'); + +declare const assertType: (value: T) => asserts value is T; +declare const serialize: (value: T) => Serialized; + +assertType(serialize(undefined)); +assertType(serialize(null)); +assertType(serialize([1, 2, 3])); +assertType<{}>(serialize(new Set([1, 2, 3]))); +assertType<{}>( + serialize( + new Map([ + [1, '2'], + [2, '4'], + ]), + ), +); +assertType(serialize(new Permissions(Permissions.FLAGS.ATTACH_FILES))); +assertType(serialize(new Intents(Intents.FLAGS.GUILDS))); +assertType( + serialize( + new Collection([ + [1, '2'], + [2, '4'], + ]), + ), +); +assertType(serialize(Symbol('a'))); +assertType(serialize(() => {})); +assertType(serialize(BigInt(42))); From 52ec31fff96bca38ae4300ee086680c290c5a2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Rom=C3=A1n?= Date: Mon, 28 Jun 2021 16:38:04 +0200 Subject: [PATCH 2/2] fix: unwrap promises Also added tests to make sure they work --- typings/index.d.ts | 18 +++++++++--------- typings/index.ts | 12 ++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index 8b9f5cc36275..ded15e83bf2a 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -133,7 +133,7 @@ declare enum WebhookTypes { 'Channel Follower' = 2, } -type Awaited = T | Promise; +type Awaited = T | PromiseLike; declare module 'discord.js' { import BaseCollection from '@discordjs/collection'; @@ -1756,14 +1756,14 @@ declare module 'discord.js' { public readonly ids: number[]; public mode: ShardingManagerMode; public parentPort: any | null; - public broadcastEval(fn: (client: Client) => T): Promise[]>; - public broadcastEval(fn: (client: Client) => T, options: { shard: number }): Promise>; + public broadcastEval(fn: (client: Client) => Awaited): Promise[]>; + public broadcastEval(fn: (client: Client) => Awaited, options: { shard: number }): Promise>; public broadcastEval( - fn: (client: Client, context: Serialized

) => T, + fn: (client: Client, context: Serialized

) => Awaited, options: { context: P }, ): Promise[]>; public broadcastEval( - fn: (client: Client, context: Serialized

) => T, + fn: (client: Client, context: Serialized

) => Awaited, options: { context: P; shard: number }, ): Promise>; public fetchClientValues(prop: string): Promise; @@ -1788,14 +1788,14 @@ declare module 'discord.js' { public totalShards: number | 'auto'; public shardList: number[] | 'auto'; public broadcast(message: any): Promise; - public broadcastEval(fn: (client: Client) => T): Promise[]>; - public broadcastEval(fn: (client: Client) => T, options: { shard: number }): Promise>; + public broadcastEval(fn: (client: Client) => Awaited): Promise[]>; + public broadcastEval(fn: (client: Client) => Awaited, options: { shard: number }): Promise>; public broadcastEval( - fn: (client: Client, context: Serialized

) => T, + fn: (client: Client, context: Serialized

) => Awaited, options: { context: P }, ): Promise[]>; public broadcastEval( - fn: (client: Client, context: Serialized

) => T, + fn: (client: Client, context: Serialized

) => Awaited, options: { context: P; shard: number }, ): Promise>; public createShard(id: number): Shard; diff --git a/typings/index.ts b/typings/index.ts index a3c5f16113e5..1934d54f3796 100644 --- a/typings/index.ts +++ b/typings/index.ts @@ -9,6 +9,8 @@ import { MessageEmbed, Permissions, Serialized, + ShardClientUtil, + ShardingManager, } from 'discord.js'; const client: Client = new Client({ @@ -58,6 +60,7 @@ client.on('message', ({ channel }) => { client.login('absolutely-valid-token'); +// Test type transformation: declare const assertType: (value: T) => asserts value is T; declare const serialize: (value: T) => Serialized; @@ -86,3 +89,12 @@ assertType( assertType(serialize(Symbol('a'))); assertType(serialize(() => {})); assertType(serialize(BigInt(42))); + +// Test type return of broadcastEval: +declare const shardClientUtil: ShardClientUtil; +declare const shardingManager: ShardingManager; + +assertType>(shardingManager.broadcastEval(() => 1)); +assertType>(shardClientUtil.broadcastEval(() => 1)); +assertType>(shardingManager.broadcastEval(async () => 1)); +assertType>(shardClientUtil.broadcastEval(async () => 1));