🦁

関数でタイプセーフじゃないと思ったらstrictがオフってた

2022/01/16に公開

タイプセーフじゃないせいで不具合が発生し少しハマったので反省の意味も込めてメモ。

下記のようなコードが書いていた。

type FuncType = (obj: { a: number }) => void;
type FuncTypeWithExtraKey = (obj: { a: number; b: number }) => void;

const func = (fn: FuncType) => {
  fn({ a: 2 });
};

const func2: FuncTypeWithExtraKey = ({ a, b }) => {
  if (a !== undefined) {
    console.log("a is undefined");
  }
  if (b !== undefined) {
    console.log("b is undefined");
  }
};

func(func2);

FuncType という型をもつ関数を引数に取る関数 func を用意する。FuncType は引数に a というキーだけを持つオブジェクトを受けとって戻り値の型が void な型。
また FuncTypeWithExtraKey という型で定義される func2 という関数も用意する。
FuncTypeWithExtraKey は引数に a と b というキーをもつオブジェクトを受け取って戻り値の型が void な型。

FuncType と FuncTypeWithExtraKey は引数の型が異なるので func に対して func2 を代入できないはずなのに代入できてしまう。

下記の例では func 内で func2 を読んでいるのだが、func から func2 をみるとキーが a しかないと思っているので b も渡そうとすると怒られる。
しかし、func2 ないでは a も b ももちろん使うことができるので b が undefined な状態で呼ばれてしまうことになる。

こんな不具合あるわけ...と思って tsconfig.json みたら strictfalse になってた(汗
stricttrue にしたらしっかり怒られるようになった。
ちなみに今回のケースだけであればstrictFunctionTypesだけで十分だがハマらないようにするためにも基本 strict を true にしておくのが無難に思える。

Discussion