diff --git a/packages/discord.js/src/structures/Emoji.js b/packages/discord.js/src/structures/Emoji.js index 1be75179b54b..f4c93e757c04 100644 --- a/packages/discord.js/src/structures/Emoji.js +++ b/packages/discord.js/src/structures/Emoji.js @@ -98,7 +98,7 @@ class Emoji extends Base { * reaction.message.channel.send(`The emoji used was: ${reaction.emoji}`); */ toString() { - return this.id ? formatEmoji(this.id, this.animated) : this.name; + return this.id ? formatEmoji({ animated: this.animated, id: this.id, name: this.name }) : this.name; } toJSON() { diff --git a/packages/formatters/__tests__/formatters.test.ts b/packages/formatters/__tests__/formatters.test.ts index b8b4a1e6217e..0feec150ce05 100644 --- a/packages/formatters/__tests__/formatters.test.ts +++ b/packages/formatters/__tests__/formatters.test.ts @@ -176,6 +176,40 @@ describe('Message formatters', () => { test('GIVEN animated emojiId THEN returns ""', () => { expect<``>(formatEmoji('827220205352255549', true)).toEqual(''); }); + + test('GIVEN static id in options object THEN returns "<:_:${id}>"', () => { + expect<`<:_:851461487498493952>`>(formatEmoji({ id: '851461487498493952' })).toEqual('<:_:851461487498493952>'); + }); + + test('GIVEN static id in options object WITH animated explicitly false THEN returns "<:_:${id}>"', () => { + expect<`<:_:851461487498493952>`>(formatEmoji({ animated: false, id: '851461487498493952' })).toEqual( + '<:_:851461487498493952>', + ); + }); + + test('GIVEN animated id in options object THEN returns ""', () => { + expect<``>(formatEmoji({ animated: true, id: '827220205352255549' })).toEqual( + '', + ); + }); + + test('GIVEN static id and name in options object THEN returns "<:${name}:${id}>"', () => { + expect<`<:test:851461487498493952>`>(formatEmoji({ id: '851461487498493952', name: 'test' })).toEqual( + '<:test:851461487498493952>', + ); + }); + + test('GIVEN static id and name WITH animated explicitly false THEN returns "<:${name}:${id}>"', () => { + expect<`<:test:851461487498493952>`>( + formatEmoji({ animated: false, id: '851461487498493952', name: 'test' }), + ).toEqual('<:test:851461487498493952>'); + }); + + test('GIVEN animated id and name THEN returns ""', () => { + expect<``>( + formatEmoji({ id: '827220205352255549', name: 'test', animated: true }), + ).toEqual(''); + }); }); describe('channelLink', () => { diff --git a/packages/formatters/src/formatters.ts b/packages/formatters/src/formatters.ts index 12d6dbac9e28..a33820369c98 100644 --- a/packages/formatters/src/formatters.ts +++ b/packages/formatters/src/formatters.ts @@ -336,11 +336,75 @@ export function formatEmoji( animated?: boolean, ): `<:_:${EmojiId}>` | ``; -export function formatEmoji( - emojiId: EmojiId, - animated = false, -): `<:_:${EmojiId}>` | `` { - return `<${animated ? 'a' : ''}:_:${emojiId}>`; +/** + * Formats a non-animated emoji id and name into a fully qualified emoji identifier. + * + * @typeParam EmojiId - This is inferred by the supplied emoji id + * @typeParam EmojiName - This is inferred by the supplied name + * @param options - The options for formatting an emoji + */ +export function formatEmoji( + options: FormatEmojiOptions & { animated: true }, +): ``; + +/** + * Formats an animated emoji id and name into a fully qualified emoji identifier. + * + * @typeParam EmojiId - This is inferred by the supplied emoji id + * @typeParam EmojiName - This is inferred by the supplied name + * @param options - The options for formatting an emoji + */ +export function formatEmoji( + options: FormatEmojiOptions & { animated?: false }, +): `<:${EmojiName}:${EmojiId}>`; + +/** + * Formats an emoji id and name into a fully qualified emoji identifier. + * + * @typeParam EmojiId - This is inferred by the supplied emoji id + * @typeParam EmojiName - This is inferred by the supplied emoji name + * @param options - The options for formatting an emoji + */ +export function formatEmoji( + options: FormatEmojiOptions, +): `<:${EmojiName}:${EmojiId}>` | ``; + +export function formatEmoji( + emojiIdOrOptions: EmojiId | FormatEmojiOptions, + animated?: boolean, +): `<:${string}:${EmojiId}>` | `` { + const options = + typeof emojiIdOrOptions === 'string' + ? { + id: emojiIdOrOptions, + animated: animated ?? false, + } + : emojiIdOrOptions; + + const { id, animated: isAnimated, name: emojiName } = options; + + return `<${isAnimated ? 'a' : ''}:${emojiName ?? '_'}:${id}>`; +} + +/** + * The options for formatting an emoji. + * + * @typeParam EmojiId - This is inferred by the supplied emoji id + * @typeParam EmojiName - This is inferred by the supplied emoji name + */ +export interface FormatEmojiOptions { + /** + * Whether the emoji is animated + */ + animated?: boolean; + /** + * The emoji id to format + */ + id: EmojiId; + /** + * The name of the emoji + */ + name?: EmojiName; } /**