TypeScript(TS)のコードを書いているとき、「型注釈(: numberなど)をどこまで書くべきか?」と迷ったことはありませんか?
その答えの鍵を握るのが、TSの強力な機能である型推論です。
本記事では、そもそも型推論とは何か?や、型推論の基本的な仕組みを解説しています。
さらに、開発者が型指定を省略すべきケースと、逆に明示的に型を記述すべき重要なケースを具体的な実例とともに紹介し、TypeScriptのベストプラクティスを確立するお手伝いをします。
TypeScriptの型推論とは何か?
TypeScriptの型推論とは、明示的に型の指定をしなくても、TypeScriptコンパイラがコードの文脈や値から自動的にその変数、関数、式などの型を自動で決定する機能です。
これにより、コードの記述量を減らし、可読性を高めながら、TypeScriptの最大の利点である型安全性を維持できます。
なお、TypeScriptとは何かや、型の指定方法については下記をご参考ください。
推論型の仕組み
型推論は、主に以下のルールに基づいて動作します。
初期化時の値からの推論
変数を宣言し、すぐに初期値を代入する場合、その初期値の型が変数の型として推論されます。
let count = 10; //number型
const message = "Hello"; //リテラル型
let isActive = true; //boolean型
let data = [1, 2, 3]; // 配列型(let data: number[] と推論される)リテラル型とは、コードに直接書き込まれた値そのものしか取れないことを示す型です。「Hello」であれば、Helloのみしか受け付けません。
string型やnumber型よりも、より限定的な型です。
関数の戻り値からの推論
関数がreturnする値の型に基づいて、関数の戻り値の型が推論されます。
function add(a: number, b: number) {
return a + b; // 戻り値は a + b の結果である number と推論される
}上記は、function add(a: number, b: number): numberと同じです。
文脈からの推論
代入先の型や、コールバック関数の呼び出し元の型など、周辺の文脈から型が推論されることもあります。
document.addEventListener('click', (event) => {
// event の型は、addEventListener の第一引数 ('click') から Event 系の型に推論される
console.log(event.target);
});event型とは、MouseEvent型やまたはそれを包含するEvent型などのことです。TypeScriptでは、イベント型は基本的に推論に任せて大丈夫です。
型推論は活用すべきか?
結論から言うと、型推論は積極的に活用すべきです。
型推論は、コードの冗長性を減らし、開発効率と可読性を向上させます。
型注釈を省略でき、コードがすっきりします。 型注釈がなくても、コンパイラが型をチェックしてくれるため、型付けの恩恵は失われません。
型推論を使うべきポイント
初期値を持つ変数の宣言
初期値を持つ変数宣言では、型注釈を省略するのがベストプラクティスです。
| ◎良い例 (型推論を活用) | ✕悪い例 (冗長な型注釈) |
const isValid = true; | const isValid: boolean = true; |
let total = 0; | let total: number = 0; |
constを積極的に使用する
letではなくconstを使用すると、TypeScriptはより厳密なリテラル型を推論してくれるため、型安全性がさらに向上します。
他にも、関数の戻り値やイベントなど、型推論が機能するところは積極的に型推論を使うことが推奨されます。
型を指定するべき場合
以下のケースでは型推論が機能せず、型安全性が失われるany型と推論されてしまうため、必ず明示的な型注釈を行います。
関数の引数
関数の引数は、外部から入力されるため、型推論が働きません。
型を明示的に指定することで、関数の契約が明確になり、呼び出し時の型チェックが保証されます。
//引数は明示、戻り値は推論
function multiply(x: number, y: number) {
return x * y; // 戻り値は number と推論される
}推論が複雑な場合や、意図を明確にしたい場合は戻り値を明示しても問題ありません。
// 戻り値がstring型であることを明示
function logAndReturn(text: string): string {
console.log(text);
return text;
}初期値がない宣言
初期値がない宣言は型を指定します。
✕ let value;
◎ let value: number;JSON.perseの結果
JSON.perseの結果は型を指定します。
✕ const obj = JSON.parse(str);
◎ const obj: MyType = JSON.parse(str);MyTypeというのは任意の型です。typeエイリアスや、interfaceによって別途指定します。
interface MyType {
userId: number;
userName: string;
data: string[];
}type MyType {
userId: number;
userName: string;
data: string[];
}

