TypeScript のベストプラクティス:モダンな開発チームのための 10 のヒント
TypeScript は静的型付けによって JavaScript に型安全性をもたらし、大規模アプリケーション開発において欠かせないツールとなっています。しかし、その機能を最大限に活用するには、適切な使い方を知ることが重要です。この記事では、実際の開発現場で役立つ TypeScript のベストプラクティスを 10 個紹介します。
1. any の使用を最小限に抑える
any型は型チェックを完全に回避するため、TypeScript の利点を損なってしまいます。
// 悪い例
function processData(data: any) {
return data.length; // 実行時エラーの可能性
}
// 良い例
function processData(data: string | string[] | { length: number }) {
return data.length; // 型安全
}
どうしても型が不明な場合は、unknown型を使用し、型の絞り込み(type narrowing)を行いましょう。
2. 型推論を活用する
TypeScript の優れた型推論機能を活用することで、冗長なコードを減らせます。
// 冗長
const name: string = "太郎";
// 型推論を活用(推奨)
const name = "太郎";
戻り値の型も多くの場合、明示的に指定しなくても推論されます。ただし、パブリック API やライブラリの関数では戻り値の型を明示することをお勧めします。
3. インターフェースと型エイリアスを適切に使い分ける
interfaceとtype(型エイリアス)は似ていますが、使用シーンが少し異なります。
// オブジェクト型の定義には interface が適している
interface User {
id: number;
name: string;
email?: string;
}
// ユニオン型や交差型、プリミティブ型のエイリアスには type が適している
type ID = string | number;
type EmailOrUsername = string;
type UserWithRole = User & { role: string };
一般的なガイドラインとしては:
- 拡張する可能性がある型には
interface - ユニオン型や交差型、関数型には
type
4. 厳格な設定を有効にする
tsconfig.jsonで厳格な型チェックを有効にしましょう:
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true
}
}
特にstrictNullChecksは、nullやundefinedに関する多くのバグを防ぐため重要です。
5. 型ガード(Type Guards)を活用する
型ガードを使用すると、特定のスコープ内での型を絞り込むことができます。
function processValue(value: string | number) {
// 型ガードを使用
if (typeof value === "string") {
// このブロック内では value は string 型として扱われる
return value.toUpperCase();
} else {
// このブロック内では value は number 型として扱われる
return value.toFixed(2);
}
}
カスタム型ガード関数も非常に便利です:
interface Car {
make: string;
model: string;
}
interface Plane {
airline: string;
flightNumber: string;
}
// カスタム型ガード関数
function isCar(vehicle: Car | Plane): vehicle is Car {
return "make" in vehicle;
}
function printVehicleInfo(vehicle: Car | Plane) {
if (isCar(vehicle)) {
// vehicle は Car 型
console.log(`${vehicle.make} ${vehicle.model}`);
} else {
// vehicle は Plane 型
console.log(`${vehicle.airline} ${vehicle.flightNumber}`);
}
}
6. ジェネリクスで再利用可能な型を定義する
ジェネリクスを使用すると、型安全性を保ちながら再利用可能なコンポーネントを作成できます。
// ジェネリックな関数
function getFirstElement<T>(array: T[]): T | undefined {
return array[0];
}
// 使用例
const numbers = [1, 2, 3];
const firstNumber = getFirstElement(numbers); // 型は number
const names = ["Alice", "Bob", "Charlie"];
const firstName = getFirstElement(names); // 型は string
7. オプショナルチェイニングと Nullish coalescing を使う
TypeScript 3.7 以降で導入されたこれらの機能は、null/undefined の扱いを簡潔にします。
// オプショナルチェイニング
const userName = user?.profile?.name; // user や profile が undefined でもエラーにならない
// Nullish coalescing
const displayName = userName ?? "ゲスト"; // userName が null または undefined なら "ゲスト" を使用
8. 型アサーションは最小限に
型アサーションは型システムを迂回するため、必要最小限にとどめるべきです。
// 避けるべき
const userInput = getUserInput() as string;
// より安全な代替手段
const userInput = getUserInput();
if (typeof userInput === "string") {
// userInput を string として使用
}
どうしても必要な場合(例:DOM の操作)のみ型アサーションを使いましょう。
9. keyof と TypeScript 組み込みユーティリティ型を活用する
TypeScript には便利な組み込みユーティリティ型がたくさんあります。
interface User {
id: number;
name: string;
email: string;
created: Date;
}
// 読み取り専用
type ReadonlyUser = Readonly<User>;
// 一部のプロパティだけを取得
type UserCredentials = Pick<User, "email" | "id">;
// 一部のプロパティを省略
type UserWithoutSensitiveInfo = Omit<User, "id" | "email">;
// オプショナルにする
type PartialUser = Partial<User>;
// keyof でプロパティ名を型として使用
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
10. モジュールの型定義を適切に行う
エクスポートする型とインターフェースを明確にし、公開 API を整理しましょう。
___
// 冗長
const name: string = "太郎";
// 型推論を活用(推奨)
const name = "太郎";0___
TypeScriptベストプラクティスの要点
TypeScript は、適切に使うことで大きな恩恵をもたらします。本記事で紹介したベストプラクティスを順守することで、より型安全で保守性の高いコードを書けるようになるでしょう。
チーム開発では、これらのプラクティスを共有し、一貫した方法で TypeScript を使用することが重要です。ESLint と TypeScript の統合や、チーム固有のルールを確立することも検討してみてください。
TypeScript の型システムは非常に強力で、日々進化しています。公式ドキュメントを定期的にチェックして、新機能や改善点についての知識を更新しましょう。
ご相談・お問い合わせはこちら