【入門編】 strictFunctionTypesによる関数型の厳格化 – TypeScript実践ガイド

こんにちは!TypeScriptの世界へようこそ。
日々コードを書いていると、「あれ、この関数、本来なら渡せるはずなのにエラーになるぞ?」とか、「逆に、なんでこんな危険な代入が通っちゃうの?」なんて場面に遭遇することはありませんか?

今日は、そんなTypeScriptの「深淵」に触れる、でもめちゃくちゃ大切な設定`strictFunctionTypes`についてお話しします。

難しく聞こえるかもしれませんが、大丈夫。この設定は、言ってみれば「あなたのコードのガードマン」です。一緒に紐解いていきましょう。

—

そもそも「関数」の代入って、そんなに危ないの?

TypeScriptの`tsconfig.json`には、たくさんの設定がありますが、その中でも`strictFunctionTypes`は、関数の「型」が正しく守られているかを厳しくチェックする役割を持っています。

ここで一つ、身近な例え話をしましょう。

あなたは「果物なら何でも受け取れるジュース屋さん」を経営しているとします。

  • あなたの店のルール: 「どんな果物でも、とりあえずミキサーに入れてジュースにします!」

さて、ここに「リンゴ専用のジュース屋さん」の店員さんがやってきました。

  • リンゴ専用店のルール: 「私はリンゴしか扱わないし、リンゴ以外は拒否します!」

これ、もしあなたが「何でもいいからジュースにして!」と頼まれたとき、リンゴ専用店の店員さんに任せたらどうなるでしょう?
もしあなたが「じゃあ、バナナをお願い」と渡したら……リンゴ専用店の店員さんは困ってしまいますよね。そう、「リンゴしか扱えない人」に「バナナ」を押し付けるのは事故のもとなんです。

TypeScriptは、この「押し付け」を未然に防ぐために、関数の代入ルールを厳格にしています。これが`strictFunctionTypes`の正体です。

—

コードで見てみよう

言葉だけだと難しいので、実際のコードを見てみましょう。

// 1. まずは「果物」の型を用意します
interface Fruit {
name: string;
}

// 2. 「リンゴ」は果物の一種です
interface Apple extends Fruit {
color: string;
}

// 3. 「何でも扱える」関数
type FruitHandler = (f: Fruit) => void;

// 4. 「リンゴだけ扱える」関数
type AppleHandler = (a: Apple) => void;

// さて、ここで代入が起こります
let myHandler: FruitHandler = (f: Fruit) => {
console.log(`果物を処理中: ${f.name}`);
};

// 【重要】本来、これは危険な代入です
// 「何でも受け取れる」はずの場所に「リンゴしか受け取れない」関数を代入すると…
// strictFunctionTypesが有効だと、ここでTypeScriptは止めてくれます!
myHandler = (a: Apple) => {
console.log(`リンゴを処理中: ${a.color}`);
};

なぜこれがダメなのか?

もし`myHandler`に`Apple`専用の関数を代入してしまうと、後から誰かが「バナナ(FruitだけどAppleではない)」をこの関数に渡した瞬間に、プログラムがクラッシュしてしまいますよね。

`strictFunctionTypes`を`true`にしておくと、TypeScriptは「おい!その代入は後々バグの温床になるぞ!」と、親切に赤波線で教えてくれるようになるんです。

—

「反変性(はんぺんせい)」という難解な言葉の正体

現場のドキュメントやネットの記事で「反変性(Contravariance)」という言葉が出てきて挫折したことはありませんか?
これ、実は今の話そのものです。

  • 共変(きょうへん): 同じ方向を向くこと。
  • 反変(はんぺん): 逆を向くこと。

関数の引数は、受け入れる側の範囲が「広ければ広いほど安全」です。
「リンゴ専用」の人より「果物全般OK」の人の方が、色々なものを受け取れますよね。

だから、「引数の型は、より広い範囲(親の型)を受け入れられる関数でなければならない」という逆転のルールが働いています。これを数学的にカッコよく言うと「反変性」というだけのこと。怖がる必要はありませんよ!

—

設定はどうすればいいの?

設定は非常に簡単です。`tsconfig.json`を開いて、以下のように記述するだけ。

{
“compilerOptions”: {
“strict”: true,
“strictFunctionTypes”: true
}
}

「あれ? `strict: true` にしてるよ!」という方、素晴らしいです!実は `strict: true` をオンにすると、この `strictFunctionTypes` も自動的に有効になります。

もし、どうしても古いコードとの兼ね合いで……という特殊な事情がない限り、基本的には `true` にしておくのが、現代のフロントエンド開発における「正義」であり、あなたの身を守る盾になります。

—

最後に:つまずいてしまったあなたへ

もし、`strictFunctionTypes`をオンにした途端、今まで動いていたコードにエラーがたくさん出てパニックになったら……それは「TypeScriptがあなたに、もっと安全なコードの書き方を教えようとしているサイン」です。

エラーが出たら、それは「あ、この関数はもっと広い型を受け取れるようにしておかないと危ないんだな」と気づくチャンス。一つずつ丁寧に型を広げていけば、あなたの書くプログラムは驚くほど堅牢で、誰が読んでも納得できる美しいコードに変わっていきます。

焦らなくて大丈夫。TypeScriptと一緒に、少しずつレベルアップしていきましょう!

また何か詰まったら、いつでも聞きに来てくださいね。応援しています!

コメント

タイトルとURLをコピーしました