こんにちは!TypeScriptの世界へようこそ。
日々コードを書いていると、「型」という言葉に少し身構えてしまう瞬間、ありますよね。特に`tsconfig.json`に並ぶ謎のオプションたち。その中でも、今回取り上げる`strictFunctionTypes`は、一見すると難解な「数学用語」の匂いがプンプンしますが、実は「お買い物の失敗を防ぐためのルール」だと考えると、すんなり理解できるんです。
さあ、肩の力を抜いて、一緒に紐解いていきましょう。
—
「関数の代入」って、実は危ない橋を渡っている?
TypeScriptを使っていると、ある関数を別の変数に代入したくなることがありますよね。でも、実はこれ、ルールを間違えると「実行時にエラーでアプリが落ちる」という悲劇を招くんです。
まず、「動物を扱う関数」を例に考えてみましょう。
// すべての動物を扱う関数
type AnimalHandler = (animal: { name: string }) => void;
// 犬だけを扱う関数
type DogHandler = (dog: { name: string; bark: () => void }) => void;
ここで、直感的には「犬も動物なんだから、`DogHandler`が必要なところに`AnimalHandler`を渡してもいいのでは?」と思いがちです。でも、TypeScriptはここで「ちょっと待った!」と警告を出してくれます。これが`strictFunctionTypes`の役割です。
なぜダメなのか?(身近な例え話)
想像してみてください。あなたは「犬専門のドッグトレーナー」だとします。
そこへ、「どんな動物でもいいから連れてきて」と言いながら、ただの「生き物」を渡されたらどうでしょう?
あなたは「ワン!」と鳴かせる訓練をしようとしますが、渡されたのが「ハムスター」だったら……? 訓練は失敗し、現場は大混乱ですよね。
- `AnimalHandler`(どんな動物でもOK)は、実は「鳴き声(bark)」という機能を持っていないかもしれません。
- `DogHandler`(犬専用)は、必ず「鳴き声」という機能を持っていることを期待しています。
だから、「どんな動物でもいい」という雑な指定の関数を、「犬専用」という厳しい条件の場所に代入するのは、TypeScriptにとって「型安全じゃない(危ない!)」という判断になるんです。
—
strictFunctionTypesをONにする理由
`tsconfig.json`で `strict: true` にしている場合、この`strictFunctionTypes`は自動的にONになります。
このオプションをONにすると、TypeScriptは「関数を代入するとき、引数の型が本当に安全か?」を厳しくチェックしてくれます。もし「あれ、これだと中身が足りなくて困るかも?」という危うい代入をしようとすると、即座に赤い波線で教えてくれるんです。
「あ、今自分は危ないことをしようとしていたんだ!」と気づかせてくれる、頼もしいガードマンのような存在ですね。
コードで確認してみよう
以下のコードをエディタに貼り付けてみてください。`strictFunctionTypes`が有効だと、最後の一行でエラーが出るはずです。
// 犬専用の型
interface Dog {
name: string;
bark: () => void;
}
// 一般的な動物の型
interface Animal {
name: string;
}
// 犬専用のトレーナー関数
const trainDog = (dog: Dog) => {
dog.bark(); // ここで「鳴け!」と命令する
};
// どんな動物でもいいから受け取る関数
const handleAnyAnimal = (animal: Animal) => {
console.log(animal.name);
};
// 【重要】ここでエラーになります!
// 「どんな動物でも扱えるはずの関数」を、「犬専用のトレーナー」として代入しようとしているからです。
// もしこれが許されると、trainDogの中で「犬じゃない動物」が来てエラーになります。
const myHandler: (dog: Dog) => void = handleAnyAnimal;
—
初学者がつまずかないためのワンポイント・アドバイス
「型が合わないって怒られたけど、どうすればいいの?」と焦る必要はありません。まずは以下のことを思い出してください。
1. 「広い型」と「狭い型」を意識する:
`Animal`は広い(何でもいい)、`Dog`は狭い(犬だけ)。広いものを、狭いところに押し込もうとすると、TypeScriptは「おっと、その箱には入らないよ」と止めてくれるんです。
2. エラーは敵ではなく味方:
TypeScriptのエラーは、あなたがアプリを公開した後に発生するかもしれない「謎のクラッシュ」を、開発中に先回りして教えてくれているだけです。
3. 無理に直そうとしない:
もし代入したいなら、関数の中身で「ちゃんとその動物が犬かどうか」を確認する処理(型ガードといいます)を書けば、TypeScriptも納得してくれますよ。
—
最後に
`strictFunctionTypes`という名前を聞くと、「反変性(contravariance)」なんていう難しい概念を思い出して身構えてしまうかもしれません。でも、結局のところ、これは「プログラムという道具箱の中で、用途に合わない部品を無理やり使おうとするのを防ぐための、優しさあふれるルール」なんです。
TypeScriptは、あなたの書いたコードを誰よりも心配してくれているパートナーです。エラーが出たら「あ、心配してくれてありがとう!」と心の中でつぶやいて、そのメッセージをヒントに少しだけコードを修正してみてください。
そうやって一つずつ積み重ねていけば、気づいたときには、あなたはもうTypeScriptの達人になっているはずですよ。応援しています!

コメント