Halcyon Days

工場DX担当者のメモ書き

MENU

リテラル型をうまく引数で渡せなくてはまったときに書いたメモ

作成したメソッドのテストコードを書いていた時に、リテラル型のうまく渡せずハマってしまった。

無事に解消したので、その時にやったことをメモ書きしておく。

どのようなエラーが発生していたか?

型定義に下記のようなリテラル型が定義してあった。

xPosition: 1 | 2;

そのため、テストコードでもこれに合うように「1」を引き渡した。

仮の関数を func とすると下記のようになる。

func({
    // 他の引数
    xPosition: 1,
}

そして npm test コマンドでテストを実行すると

Types of property 'xPosition' are incompatible.
Type 'number' is not assignable to type '1 | 2'.

というエラーが発生した。

リテラル型の通りに「1」を渡していたはずだったがエラーが発生してしまった。

なぜこのようなエラーが発生したか?

引数の型を明示的に指定していなかったことが原因だった。

今回の場合だと自分は number 型の 1 を引数に渡していたのだが、TypeScriptはこのような場合に他の数値も受け取れると判断してしまうっぽい。

そのため、1と2以外の数も受け取れると判断してしまう。

したがって、リテラル型に指定されている以外の数も受け取れるとなり、エラーが発生してしまう。

このため「これは 1 だよ」ということを明示的に指定してやらねばならない。

明示的に型を指定する

エラーの解消には as アサーションを使った。

func({
    // 他の引数
    xPosition: 1 as 1,
}

このようにすることで「 11 というリテラル型」ということを明示的に指定できる。

編集後、再度テストコマンドを叩くとエラーが解消された。

テスト対象のメソッド

下記のような感じのサンプルコード。

型定義

type Position = {
  xPosition: 1 | 2;
  yPosition: 1 | 2;
};

メソッド

export function setPosition(position: Position) {
  console.log(
    `Setting position: X = ${position.xPosition}, Y = ${position.yPosition}`
  );
}

テスト

import { setPosition } from './path/to/setPosition';

describe('setPosition', () => {
  it('[OK] xPosition が 1, yPosition が 2', () => {
    const consoleSpy = jest.spyOn(console, 'log');
    setPosition({ xPosition: 1 as 1, yPosition: 2 as 2 });
    expect(consoleSpy).toHaveBeenCalledWith('Setting position: X = 1, Y = 2');
    consoleSpy.mockRestore();
  });

  it('[OK] xPosition が 2, yPosition が 1 の場合', () => {
    const consoleSpy = jest.spyOn(console, 'log');
    setPosition({ xPosition: 2 as 2, yPosition: 1 as 1 });
    expect(consoleSpy).toHaveBeenCalledWith('Setting position: X = 2, Y = 1');
    consoleSpy.mockRestore();
  });
});