📝

jsdoc + ts-check 環境でdiscord.jsのGuildMemberをMockする

2024/03/17に公開

かなりニッチであることは自覚しています、、、

出来るなら素直にTypescriptで書いた方が速いのでは?と思いますが、jsdoc + ts-checkという環境で開発してみたかったんです。

環境

前提

discord.jsはつくりとしてはEasy寄りだと感じています。API呼び出しとかめちゃくちゃラップされてるし、サジェスト見ながら適当に書いてもまあまあ書ける感じです。

そういうことで自分で定義している関数の引数にもDiscord.jsのオブジェクトをそのまま使っています。

/**
 * @param {import('discord.js').GuildMember} member
 * @returns string
 */
export const getDisplayName = (member) => {
  return member.nickname || member.user.username
}

課題

テストコードを書こうとするとGuildMemberの生成が難儀。

// @ts-check
import { test } from 'vitest';
import { GuildMember} from 'discord.js';
import { getDisplayName } from './get-display-name.js';

test(getDisplayName, () => {
  // これはエラー
  // Constructor of class 'GuildMember' is private and only accessible within the class declaration.ts(2673)
  // const actual = getDisplayName(new GuildMember);

  // これはエラー
  // Type '{}' is missing the following properties from type 'GuildMember': _roles, avatar, bannable, dmChannel, and 40 more.ts(2740)
  // const actual = getDisplayName({ nickname: 'user1' });

  // これはエラー
  // Argument of type '{ nickname: string; }' is not assignable to parameter of type 'Partial<GuildMember>'.
  //   The types returned by 'toString()' are incompatible between these types.
  //     Type 'string' is not assignable to type '`<@${string}>`'.ts(2345)
  // const actual = getDisplayName(makeGuildMember({ nickname: 'user1' }));

  // これは通るが、補完が効かないのでやりたくない
  const actual = getDisplayName(makeGuildMember2({ nickname: 'user1' }));
});

/**
 * @param {Partial<import('discord.js').GuildMember>} member
 * @returns {import('discord.js').GuildMember}
 */
const makeGuildMember = (member) => {
  // @ts-expect-error
  return member;
};

/**
 * @param {any} member
 * @returns {import('discord.js').GuildMember}
 */
const makeGuildMember2 = (member) => {
  return member;
};

暫定対応

とりあえずPickしている

/**
 * @param {Pick<Partial<import('discord.js').GuildMember>, 'nickname'>} member
 * @returns {import('discord.js').GuildMember}
 */
const makeGuildMember = (member) => {
  // @ts-expect-error
  return member;
};

後で試したい

  • vitestのmockでどうにかする

参考

Discussion