実務でのTypeScript、型ってどこまでやる?

TypeScriptを使った開発が当たり前になりつつある今、「どこまで型をきっちり書くべき?」と悩む場面は少なくありません。型安全を意識するあまりに冗長なコードになることもあれば、逆に any で逃げすぎて型の恩恵を受けられないこともあります。
この記事では、実際の開発経験を踏まえつつ「これくらいやっておけば安心」という現場でのバランス感覚を紹介します。
目次
型注釈は「必要なときだけ」でOK
const foo = “hello” as string;
このように明らかなリテラルに対して as string をつけるのは基本的に不要です。「推論で足りるところは任せてしまう」というスタンスで問題ないように感じます。
ただし、関数の戻り値・props・外部APIとのインターフェースなど、境界となる部分には明示的な型定義が必要です。
type と interface、どっちを使う?
結論としては、どちらでもよいです。ただし、プロジェクト内で統一することが重要です。
・type:ユニオン型やマップ型など応用が利きやすい
・interface:拡張性(extends)に強い
ReactのProps定義など、どちらでも書ける場面は多いですが、チーム内で「このプロジェクトでは type を使う」などルールを決めておくと混乱を防げます。
イベントハンドラなどの型は手を抜かない
例えば、Reactでボタンのクリックイベントを扱う場合、よくあるのが以下のような書き方。
type Props = {
onClick: () => void;
}
一見問題なさそうですが、以下のように書いたほうが保守性が高くなります。
type Props = React.ButtonHTMLAttributes<HTMLButtonElement>;
こうしておけば、disabled や type などの属性も型で補完され、将来的な変更にも強くなります。
JSXでは <string> より as string を使う
const name = “Name” as string;
const name2 = <string>”Name”; // 非推奨
どちらも意味は同じですが、JSXでは <string> を使うとタグと解釈されてしまう可能性があります。そのため、実務では as string を使うのが基本です。
any を使ってもいいけど「逃げ道」にしない
開発初期や検証段階では any を使って「まず動かす」のは悪いことではありません。ただし、最終的には具体的な型に書き換える意識が必要です。
const data: unknown = getData();
if (typeof data === “string”) {
// 型チェックで扱えるようになる
}
unknown などを使って、段階的に型を絞っていくのも選択肢の一つです。
「この型、いる?いらない?」の見極めポイント
実際の開発現場では、次のような問題に遭遇することがあります。
・型が細かすぎて修正が大変
・型が曖昧すぎてバグにつながった
・type と interface が混在していて統一感がない
これらを避けるには、「推論に任せられる部分は任せて、外部との境界はきちんと守る」というスタンスが現実的です。
まとめ:「型」はツール。全部を制覇しなくても大丈夫
TypeScriptの型システムは非常に奥が深く、Mapped型やConditional型、Utility Typesなど覚えることは無数にあります。
でも、実務では以下のポイントさえ押さえておけば安心です。
・基本は型推論に任せる
・外部からアクセスされる部分(Props、APIレスポンス、戻り値など)には明示的な型を書く
・チーム内で type または interface を統一する
・JSX内では <string> より as string を使う
・any は一時的な避難所。最終的には具体的な型にする
TypeScriptは「完璧にするため」ではなく、「チーム全体が安心して書けるコード」のためのツール。だからこそ、適度な型定義とルールが大切だと感じました。