From 980243f2d5d04b6ab240a5a5caa0df810da8291e Mon Sep 17 00:00:00 2001 From: Sugden <28943913+NotSugden@users.noreply.github.com> Date: Wed, 12 Aug 2020 20:26:59 +0100 Subject: [PATCH] fix(Partials): correctly set properties as nullable (#4636) --- src/structures/GuildMember.js | 27 +++++---- src/structures/Message.js | 87 +++++++++++++++++----------- src/structures/User.js | 106 ++++++++++++++++++++-------------- typings/index.d.ts | 21 ++++--- 4 files changed, 143 insertions(+), 98 deletions(-) diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 61e56a62a..b01dfa013 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -29,13 +29,6 @@ class GuildMember extends Base { */ this.guild = guild; - /** - * The user that this guild member instance represents - * @type {User} - * @name GuildMember#user - */ - if (data.user) this.user = client.users.add(data.user, true); - /** * The timestamp the member joined the guild at * @type {?number} @@ -78,13 +71,19 @@ class GuildMember extends Base { } _patch(data) { - if (typeof data.nick !== 'undefined') this.nickname = data.nick; + if ('user' in data) { + /** + * The user that this guild member instance represents + * @type {User} + * @name GuildMember#user + */ + this.user = this.client.users.add(data.user, true); + } - if (data.joined_at) this.joinedTimestamp = new Date(data.joined_at).getTime(); - if (data.premium_since) this.premiumSinceTimestamp = new Date(data.premium_since).getTime(); - - if (data.user) this.user = this.guild.client.users.add(data.user); - if (data.roles) this._roles = data.roles; + if ('nick' in data) this.nickname = data.nick; + if ('joined_at' in data) this.joinedTimestamp = new Date(data.joined_at).getTime(); + if ('premium_since' in data) this.premiumSinceTimestamp = new Date(data.premium_since).getTime(); + if ('roles' in data) this._roles = data.roles; } _clone() { @@ -196,7 +195,7 @@ class GuildMember extends Base { /** * The nickname of this member, or their username if they don't have one - * @type {string} + * @type {?string} * @readonly */ get displayName() { diff --git a/src/structures/Message.js b/src/structures/Message.js index 91c0212bc..642cefb60 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -51,35 +51,62 @@ class Message extends Base { */ this.id = data.id; - /** - * The type of the message - * @type {MessageType} - */ - this.type = MessageTypes[data.type]; + if ('type' in data) { + /** + * The type of the message + * @type {?MessageType} + */ + this.type = MessageTypes[data.type]; - /** - * The content of the message - * @type {string} - */ - this.content = data.content; + /** + * Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications) + * @type {?boolean} + */ + this.system = data.type !== 0; + } else if (typeof this.type !== 'string') { + this.system = null; + this.type = null; + } - /** - * The author of the message - * @type {?User} - */ - this.author = data.author ? this.client.users.add(data.author, !data.webhook_id) : null; + if ('content' in data) { + /** + * The content of the message + * @type {?string} + */ + this.content = data.content; + } else if (typeof this.content !== 'string') { + this.content = null; + } - /** - * Whether or not this message is pinned - * @type {boolean} - */ - this.pinned = data.pinned; + if ('author' in data) { + /** + * The author of the message + * @type {?User} + */ + this.author = this.client.users.add(data.author, !data.webhook_id); + } else if (!this.author) { + this.author = null; + } - /** - * Whether or not the message was Text-To-Speech - * @type {boolean} - */ - this.tts = data.tts; + if ('pinned' in data) { + /** + * Whether or not this message is pinned + * @type {?boolean} + */ + this.pinned = Boolean(data.pinned); + } else if (typeof this.pinned !== 'boolean') { + this.pinned = null; + } + + if ('tts' in data) { + /** + * Whether or not the message was Text-To-Speech + * @type {?boolean} + */ + this.tts = data.tts; + } else if (typeof this.tts !== 'boolean') { + this.tts = null; + } /** * A random number or string used for checking message delivery @@ -87,13 +114,7 @@ class Message extends Base { * lost if re-fetched * @type {?string} */ - this.nonce = data.nonce; - - /** - * Whether or not this message was sent by Discord, not actually a user (e.g. pin notifications) - * @type {boolean} - */ - this.system = data.type !== 0; + this.nonce = 'nonce' in data ? data.nonce : null; /** * A list of embeds in the message - e.g. YouTube Player @@ -122,7 +143,7 @@ class Message extends Base { * The timestamp the message was last edited at (if applicable) * @type {?number} */ - this.editedTimestamp = data.edited_timestamp ? new Date(data.edited_timestamp).getTime() : null; + this.editedTimestamp = 'edited_timestamp' in data ? new Date(data.edited_timestamp).getTime() : null; /** * A manager of the reactions belonging to this message diff --git a/src/structures/User.js b/src/structures/User.js index 93689606d..e073f988e 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -26,60 +26,78 @@ class User extends Base { */ this.id = data.id; - /** - * Whether or not the user is a bot - * @type {boolean} - * @name User#bot - */ - this.bot = Boolean(data.bot); - this._patch(data); } _patch(data) { - /** - * The username of the user - * @type {?string} - * @name User#username - */ - if (data.username) this.username = data.username; + if (typeof this.bot !== 'boolean') { + /** + * Whether or not the user is a bot + * @type {?boolean} + * @name User#bot + */ + this.bot = 'bot' in data ? Boolean(data.bot) : null; + } - /** - * A discriminator based on username for the user - * @type {?string} - * @name User#discriminator - */ - if (data.discriminator) this.discriminator = data.discriminator; + if ('username' in data) { + /** + * The username of the user + * @type {?string} + * @name User#username + */ + this.username = data.username; + } else if (typeof this.username !== 'string') { + this.username = null; + } - /** - * The ID of the user's avatar - * @type {?string} - * @name User#avatar - */ - if (typeof data.avatar !== 'undefined') this.avatar = data.avatar; + if ('discriminator' in data) { + /** + * A discriminator based on username for the user + * @type {?string} + * @name User#discriminator + */ + this.discriminator = data.discriminator; + } else if (typeof this.discriminator !== 'string') { + this.discriminator = null; + } - if (typeof data.bot !== 'undefined') this.bot = Boolean(data.bot); + if ('avatar' in data) { + /** + * The ID of the user's avatar + * @type {?string} + * @name User#avatar + */ + this.avatar = data.avatar; + } else if (typeof this.avatar !== 'string') { + this.avatar = null; + } - /** - * Whether the user is an Official Discord System user (part of the urgent message system) - * @type {?boolean} - * @name User#system - */ - if (typeof data.system !== 'undefined') this.system = Boolean(data.system); + if ('system' in data) { + /** + * Whether the user is an Official Discord System user (part of the urgent message system) + * @type {?boolean} + * @name User#system + */ + this.system = Boolean(data.system); + } - /** - * The locale of the user's client (ISO 639-1) - * @type {?string} - * @name User#locale - */ - if (data.locale) this.locale = data.locale; + if ('locale' in data) { + /** + * The locale of the user's client (ISO 639-1) + * @type {?string} + * @name User#locale + */ + this.locale = data.locale; + } - /** - * The flags for this user - * @type {?UserFlags} - * @name User#flags - */ - if (typeof data.public_flags !== 'undefined') this.flags = new UserFlags(data.public_flags); + if ('public_flags' in data) { + /** + * The flags for this user + * @type {?UserFlags} + * @name User#flags + */ + this.flags = new UserFlags(data.public_flags); + } /** * The ID of the last message sent by the user, if one was sent diff --git a/typings/index.d.ts b/typings/index.d.ts index c3e1cb4f7..bb56f3101 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -2887,7 +2887,7 @@ declare module 'discord.js' { } & { [K in keyof Omit< T, - 'client' | 'createdAt' | 'createdTimestamp' | 'id' | 'partial' | 'fetch' | O + 'client' | 'createdAt' | 'createdTimestamp' | 'id' | 'partial' | 'fetch' | 'deleted' | O >]: T[K] extends Function ? T[K] : T[K] | null; // tslint:disable-line:ban-types }; @@ -2922,33 +2922,38 @@ declare module 'discord.js' { interface PartialGuildMember extends Partialize< GuildMember, - 'bannable' | 'displayColor' | 'displayHexColor' | 'displayName' | 'guild' | 'kickable' | 'permissions' | 'roles' + 'bannable' | 'displayColor' | 'displayHexColor' | 'displayName' | 'guild' | 'kickable' | 'permissions' | 'roles' | 'manageable' | 'presence' | 'voice' > { readonly bannable: boolean; readonly displayColor: number; readonly displayHexColor: string; readonly displayName: string; guild: Guild; + readonly manageable: boolean; joinedAt: null; joinedTimestamp: null; readonly kickable: boolean; readonly permissions: GuildMember['permissions']; + readonly presence: GuildMember['presence']; readonly roles: GuildMember['roles']; + readonly voice: GuildMember['voice']; } interface PartialMessage extends Partialize< Message, - 'attachments' | 'channel' | 'deletable' | 'editable' | 'mentions' | 'pinnable' | 'system' | 'url' + 'attachments' | 'channel' | 'deletable' | 'editable' | 'mentions' | 'pinnable' | 'url' | 'flags' | 'edits' | 'embeds' > { attachments: Message['attachments']; channel: Message['channel']; readonly deletable: boolean; readonly editable: boolean; + readonly edits: Message['edits']; + embeds: Message['embeds']; + flags: Message['flags']; mentions: Message['mentions']; readonly pinnable: boolean; reactions: Message['reactions']; - system: boolean; readonly url: string; } @@ -2958,10 +2963,12 @@ declare module 'discord.js' { type PartialTypes = 'USER' | 'CHANNEL' | 'GUILD_MEMBER' | 'MESSAGE' | 'REACTION'; - interface PartialUser extends Partialize { - discriminator: undefined; - username: undefined; + interface PartialUser extends Partialize { + flags: User['flags']; + locale: User['locale']; + system: User['system']; readonly tag: null; + username: null; } type PresenceStatusData = ClientPresenceStatus | 'invisible';