in in 演算子によるナローイング
最終更新:2026-10-22
in in 演算子によるナローイング
in 演算子はあるプロパティ名がオブジェクト上に存在するかを調べ、TypeScript はこれを利用してユニオン型を「そのプロパティを持つメンバー」へナローイングます。ユニオンの各メンバーに共通の判別フィールドがなく、インターフェース(instanceof が使えない)である場合、in が最も手軽な構造の区別手段になります。
| グループ | ナローイングとアサーション |
|---|---|
| 種類 | 演算子 |
| strict モード | 不要 |
ℹ️ 説明 エディタは TypeScript を JavaScript にトランスパイルして実行します(型チェックなし)。型チェック結果は各サンプルの出力を参照してください。
📝 構文
interface Bird { fly: () => void }
interface Fish { swim: () => void }
function move(animal: Bird | Fish) {
if ("swim" in animal) {
animal.swim(); // Fish にナローイング
} else {
animal.fly(); // Bird にナローイング
}
}
⚙️ パラメータ
| "key" in obj | 実行時に key が obj のプロパティ(プロトタイプチェーン上のものも含む)であるかを調べ、boolean を返します。TS は同時に obj をそのプロパティを含むユニオンのメンバーへナローイングます |
|---|
戻り値:in 式は boolean を返します。ナローイングはコンパイル時に起こり、ユニオンのメンバー間のプロパティの相互排他性(あるプロパティを持つか持たないか)に依存します。
▶ サンプル
下のコードを編集して「試す」を押すと、トランスパイル実行結果を確認できます:
出力:
bubble...
it swims
flap!
it flies
(トランスパイル後の実行出力。animal.swim() が型チェックを通るのは、in によるナローイングで animal が Fish と確定したからです。ナローイングは tsc が静的に保証し、実行時に見えるのは値だけです)
💡 ポイント
ℹ️ 説明 in は「プロパティが存在するか」を調べます。プロトタイプチェーンで継承されたプロパティも含みます。プレーンなオブジェクトには toString や constructor といった組み込みプロパティもあるため、チェックには業務のフィールド名を使いましょう。
⚠️ 注意 in によるナローイングは「プロパティの相互排他性」に依存します。2つのメンバーが同型のフィールドを共有している場合(型だけが異なる場合)、in の助けは限定的です。そのような場面では判別可能ユニオン(判別フィールドに互いに異なるリテラル値を取らせる)に切り替えましょう。
💡 ヒント in はマップ型の中心構文でもあります([K in keyof T])。ただしそれは型レベルの使い方です。ここで扱う in は実行時の操作子+コンパイル時のナローイングです。
🏷️ 関連ナローイングとアサーション
💡 関連ケース
ケースは今後追加予定です。
📚 関連チュートリアル
❓ よくある質問
Q in によるナローイングと判別可能ユニオンはどう使い分けますか?
A 各メンバーに互いに異なるリテラルのフィールド(type/status/kind など)を設計できるなら判別可能ユニオンを使いましょう。より明確で網羅性チェックにも対応します。ユニオンがサードパーティ由来で判別フィールドがない場合は、in で構造的に区別します。
Q オプショナルプロパティは in に誤認させる可能性がありますか?
A あります。オプショナルな flag?: boolean はオブジェクト上に実在しないことがあり、flag in obj が false でも別のメンバーに属するとは限りません。in を使う前に、そのプロパティが各メンバーで「必ずある」か「必ずない」かを確認しましょう。
Q プロパティを delete した後も in は正しく絞り込めますか?
A できます。delete obj.key の後、in の実行時の結果は false になり、TS はそのプロパティを含まないメンバーへナローイングます。ただし実行時の型と宣言の型がすでに一致しない可能性があります。厳密な TS では必須プロパティの delete 自体がコンパイルエラーです。