第6章 超重要:TSは型が実行時に消える👻(ここがC#と違う!)
この章はDI(依存性注入)をTypeScriptでやるときの** 返ってくるのは 入力だけの関数(ここが最高に便利😍)
分かると、あとが一気にラクになる✨
🎯 この章のゴール(ここまでできたらOK!)
- 「TypeScriptの型は、実行時に存在しない」を自分の言葉で説明できる🗣️✨ (TypeScript)
- 「だからTSのDIはC#みたいに“型から自動解決”が基本できない」を理解できる🧠💡
- 代わりに必要になる “値(token)” ベースのDI テストが爆速で安定🧪💕
1) まず結論:TSの型は“設計図”で、完成品(実行時)には残らない👻📄➡️📦

TypeScriptは JavaScriptに変換して実行されるよね。
このとき 型注釈(: string とか)や型の情報は消える。
公式ドキュメントでも「TypeScript固有のものは消える(eraseされる)」って説明されてるよ✨ (TypeScript)
たとえば👇
// ✅ TypeScript(書いてるときは型がある)
function greet(name: string) {
return "Hello, " + name;
}
出力されるJavaScriptはだいたいこう👇(イメージ)
// ✅ JavaScript(実行時。型はもういない👻)
function greet(name) {
return "Hello, " + name;
}
型は“コンパイル時のチェック用”で、動いてる最中の世界にはいないって覚えよう🧠✨ (型アサーションも実行時チェックはしてくれないよ〜⚠️) (TypeScript)
2) 「interfaceが実行時にいない」がDIで致命的になる理由💥💉
❌ やりがちな罠:interfaceをDIコンテナのキーにしたくなる
C#だと「ILogger を登録して…」みたいに、インターフェイスそのものを登録キーにできるよね。
でもTSで同じことをやろうとするとこうなる👇
interface Logger {
log(msg: string): void;
}
// ❌ これはできない(interfaceは“型”であって“値”じゃない)
container.register(Logger, ConsoleLogger);
だって Logger は 実行時に存在しないから、登録キーとして渡せないの🥲
この「型=消える」性質のせいで、TSのDIは基本的に “値(value)をキーにする” 発想が必要になるよ🔑✨
3) じゃあTSのD> I/Oは外側に追い出して、中心をPureにする✂️✨
TypeScriptでDIするときのキーはだいたいこのへん👇
✅ A. class(クラス)は実行時にいる🏛️
class ConsoleLogger {
log(msg: string) { console.log(msg); }
}
// クラス(コンストラクタ関数)は実行時に存在する=キーにできる
container.register(ConsoleLogger, () => new ConsoleLogger());
📌 ただし注意! 「抽象(interface)ではなく具象(class)に寄りがち」になって、DIP的にイヤなときがある😵💫
✅ B. string(文字列token)🧵
const LOGGER = "Logger";
container.register(LOGGER, () => new ConsoleLogger());
📌 注意! 文字列は衝突しやすい(同名の事故)🥲
✅ C. Symbol(おすすめ!衝突しない)💎
export const LOGGER = Symbol("Logger");
export type Logger = { log(msg: string): void };
container.register(LOGGER, () => new ConsoleLogger());
// 取り出すときは型引数で「これはLoggerだよ」を付ける
const logger = container.resolve<Logger>(LOGGER);
logger.log("hi!");
Symbolは実行時に存在する値だし、基本衝突しないから便利💎✨
4) 「import」も実行時に関係あるよ⚠️(型だけのつもりが地雷になるやつ)
ここ、DIと相性悪い事故ポイント🔥
✅ import type は “型だけ” を読み込む(実行時には消える)👻📦
TypeScript公式のリリースノートでも、import type は 出力に残らず完全に消えるって明言されてるよ✨ (TypeScript)
import type { Logger } from "./logger-types"; // ✅ 型だけ
// これは実行時JSには残らない(= 余計な依存や副作用を増やしにくい)
DIでありがちな「循環import🌀」や「読み込んだ瞬間に副作用ドーン💥」を避けるのに効く👍
✅ verbatimModuleSyntax:importの挙動を“素直”にする設定🧼
最近のTSでは、モジュール周りの事故を減らすために verbatimModuleSyntax みたいなオプションも用意されてるよ(import/exportをより明確に扱う)🧹✨ (TypeScript)
あと preserveValueImports は verbatimModuleSyntax のほうが今は推奨って扱いになってるよ📌 (TypeScript)
5) まとめ:この章がDIにくれる超大事な“合言葉”🧩✨
- TSの型(
RegisterDepsとして成立してるかチェックしつつ、オブジェクトの“中身の型推論”は潰さないのがsatisfiesの良さだよ〜!(TypeScript)
- だからTSのDIは「型から自動で解決!」よりも、まず 値token(Symbolとか)で組み立てる方向が現実的🔑
import typeを使うと「型だけ」を安全に扱えて、DIの地雷(循環importなど)を踏みにくい💣➡️🧯 (TypeScript)
🧪 ミニ課題(5分)✨
課題A:一文で説明してみよ📝
「TypeScriptの型が実行時に消える」ってどういうこと? 👉 30文字くらいで説明してみて😊
課題B:DI用のtokenを作ってみよ🔑
Clock(now(): number)のtokenを Symbol で作ってみてね💎
🤖 AIにお願いするなら(コピペOK✨)
- 「TypeScriptの型消失を、高校生にも分かる例えで3つ出して」
- 「interfaceをDIのキーにできない理由を、短く説明して」
- 「Symbol tokenを使った最小DI例をTypeScriptで書いて(Clock/Logger)」
📌 最新状況メモ(2026-01-16時点)
- TypeScriptの最新安定版は 5.9.3(npmと公式リリース一覧で確認できるよ) (npm)
- 公式ブログでは **TypeScript 6.0は5.9→7.0への“橋渡し”**という位置づけで、リリースは早期2026が目標と報じられてるよ (Microsoft for Developers)
(でもね!✨ バージョンが進んでも「型が実行時に消える」はTypeScriptの根っこなので、ここはずっと超重要だよ👻)
次の第7章からは、この前提の上で「じゃあ依存をどう渡す?(deps注入)」を、手を動かしながらやっていくよ〜👜💉✨