search
LoginSignup
224
Help us understand the problem. What are the problem?

posted at

updated at

Jest + TypeScriptで覚えておきたいParametersとReturnType&小技集

Jest + TypeScript でテストコードを書く際に、覚えておくととても便利だと感じたものを備忘録的に記事にいたします。

1. Parameters

まず、TypeScriptの Utility Types である Parameters<Type> です。
(Utility Typesとは、TypeScriptが標準で提供している便利な関数のような機能です)

特徴

  • 関数に対して使用する
  • Parameters<関数型> とすることで、関数の引数をタプル型 にしてくれる
  • Parameters<typeof someFun> でもOK

コード例

では、例を見てみましょう。

// 例:1
type T0 = Parameters<() => string>; // type T0 = [] || 引数がないので空タプル

// 例:2
type T1 = Parameters<(s: string) => void>; // type T1 = [s: string] || 引数がタプル型になっている

// 例:3
const someFunc = (arg: { a: number; b: string }) => void {}
type T3 = Parameters<typeof someFunc>;
/**
type T3 = [arg: {
    a: number;
    b: string;
}]
*/

2. ReturnType

続いては、同じく Utility Types である ReturnType<Type> です。

特徴

  • 関数に対して使用する
  • ReturnType<関数型> とすることで、関数の戻り値で構成される型 にしてくれる
  • ReturnType<typeof someFun> でもOK

コード例

では、例を見てみましょう。

// 例:1
type T0 = ReturnType<() => string>; // type T0 = string || 戻り値がstringなので

// 例:2
type T1 = ReturnType<(s: string) => void>; // type T1 = void

// 例:3
const someFunc = (): { a: number; b: string } => ({a: 1, b: 'string'})
type T3 = ReturnType<typeof someFunc>;
/**
type T3 = {
    a: number;
    b: string;
}
*/

3. Jestで使ってみる

2つの Utility Types を紹介させて頂きました。

ところでこの2つはどんな時に便利なのでしょうか?

もちろん色々なケースが考えられますが、
関数のテストコードを書くときにめちゃくちゃ便利 でした。

TestDataの型にParametersとReturnTypeを使った例

例えば、以下のように状態を持たない純粋な関数があったとします。

service/existsPath.ts
import isEmpty from 'lodash/isEmpty';

// args.pathに値が存在するかを確認する
export const existsPath = (args: { path: string; params: string }): boolean => {
  return !isEmpty(args.path);
};

この関数をJestを使ってテストコードを書く時に、以下のようにすると引数と戻り値の型をサクッと作れます。

test/ExistsPath.spec.ts
import { existsPath } from '@/service/existsPath';

describe('existsPathのテスト', () => {
  type TestData = {
    params: Parameters<typeof existsPath>;
    expected: ReturnType<typeof existsPath>;
  };
});

何が嬉しいか?

この type TestData が作れることで何が嬉しいのでしょう?

そうです、テストデータを準備する時にも、しっかりと 型が効く のです。

テストコードは以下のようにしてみます。

test/ExistsPath.spec.ts
import { existsPath } from '@/service/existsPath';

describe('existsPathのテスト', () => {
  type TestData = {
    params: Parameters<typeof existsPath>;
    expected: ReturnType<typeof existsPath>;
  };

  const testData: TestData = {
    params: [{ path: 'ほげ', params: '' }],
    expected: true,
  };

  test('pathに値が存在していればtrueを返す', () => {
    expect(existsPath(testData.params[0])).toBe(testData.expected);
  });
});

このコードを記述している時もインテリセンスが効いてくれます。
Screen Shot 2022-01-20 at 23.15.52.png
テストを走らせてみます。

無事通りました。
Screen Shot 2022-01-20 at 23.17.51.png

ループさせてより便利にしてみる

ここまでだと、ただ型が効いただけになりますが、
更に便利にすることができます。

testDataを配列 にして、test.eachループ させてみましょう。

「testData」と「expect」の箇所を以下のように修正します。

test/ExistsPath.spec.ts
const testData: TestData[] = [
  {
    params: [{ path: 'ほげ', params: '' }],
    expected: true,
  },
  {
    params: [{ path: '', params: '' }],
    expected: false,
  },
];

test.each(testData)('入力値と返却値が期待通りであること', (testData: TestData) => {
  expect(existsPath(...testData.params)).toBe(testData.expected);
});

テストを走らせてみます。
Screen Shot 2022-01-20 at 23.30.35.png
無事通りました。

最終的なコードは以下のようになります。

test/ExistsPath.spec.ts
import { existsPath } from '@/service/existsPath';

describe('existsPathのテスト', () => {
  type TestData = {
    params: Parameters<typeof existsPath>;
    expected: ReturnType<typeof existsPath>;
  };

  const testData: TestData[] = [
    {
      params: [{ path: 'ほげ', params: '' }],
      expected: true,
    },
    {
      params: [{ path: '', params: '' }],
      expected: false,
    },
  ];

  test.each(testData)('入力値と返却値が期待通りであること', (testData: TestData) => {
    expect(existsPath(...testData.params)).toBe(testData.expected);
  });
});

このように「ParametersとReturnType」を使うことにより、
型の情報を得ながらテストを効率的に書くことができました。

より厳密に記述すると、params も 戻り値も interface を別途切る方が綺麗かもしれませんが、
サクッと効率良くテストコードを記述するにはすごく便利だと感じました。

まとめ

  • Parameters と ReturnType は Utility Types である
  • Utility Types とは、TypeScript が標準で提供している便利な関数のような機能
  • Jest + TypeScript では Parameters と ReturnType を使うことで型の情報を得ながら、効率的に記述できた
  • 最後の最後だけど、別にJestだけじゃなくて色々なケースで使えるよ

以上となります。
お読み頂き有難うございました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
224
Help us understand the problem. What are the problem?