プロンプトとコンテキスト
ある Node.js サービスでは現在、コンテナが起動する前に TypeScript を JavaScript にコンパイルしています。チームはスクリプトや開発ツールチェーンを短縮するために、.ts ファイルを直接実行したいと考えています。組み込みの type stripping、そのサポート範囲、モジュール解決、設定の制限、テスト、および本番リリースの戦略について説明してください。
面接官が評価するポイント
- Node.js が型チェックやランタイムコード生成を行わずに型注釈を削除することを理解しているか。
- enum、ランタイム名前空間、パラメータプロパティ、デコレータを消去不能な構文(non-erasable syntax)として識別できるか。
- Node.js が
tsconfig.jsonを無視するため、パスエイリアスやターゲット変換が自動的に適用されないことを理解しているか。 - 開発スクリプト、コンパイル済みアーティファクト、依存関係、本番サービスを適切に分離できているか。
確認すべき明確化のための質問
- 対象は開発スクリプト、CLI、テスト、または長時間実行される本番サービスですか?
- コードでは enum、デコレータ、パラメータプロパティ、名前空間、またはパスエイリアスを使用していますか?
- モジュールモード、Node のバージョン、TypeScript のバージョン、およびリリースイメージを標準化できますか?
- チームは完全な型チェック、ソース変換、ソースマップ、または古い Node バージョンのサポートを必要としていますか?
30秒の回答フレームワーク
私は組み込み機能を軽量な実行機能として扱います。これは消去可能な型構文を空白に置き換え、型チェックを実行せず、enum やデコレータに対する JavaScript を生成しません。まずコードをスキャンし、Node のバージョンを固定します。tsconfig のパスエイリアスに依存する代わりに、import type、明示的な拡張子、および明確なモジュールルールを使用します。完全な TypeScript セマンティクスを必要とするサービスはコンパイラまたは tsx を維持し、組み込みパスはスクリプトや小規模なツールから開始します。CI は範囲を広げる前に、型チェック、ランタイムテスト、およびアーティファクトチェックを実行します。
ステップごとの詳細解説
1. 消去モデルの説明
Node.js は型注釈を空白に置き換えるため、ソースマップがなくてもスタックの行番号は通常一致したままになります。型チェックを行わず、JavaScript の生成が必要な構文の変換も行いません。enum、ランタイム名前空間、パラメータプロパティ、デコレータは、未サポート構文エラーを発生させます。直接実行は消去可能な構文に限定されます。
2. モジュールとインポートの固定
Node.js は CommonJS および ES module の TypeScript ファイルをサポートしており、実際のモードはパッケージ構成、拡張子、呼び出し方法に依存します。型のインポートには import type を使用する必要があります。そうしないと、消去されたインポートが値として扱われ、実行時に失敗します。Node が変換できないエイリアスではなく、解決可能な相対拡張子と package.json imports を使用してください。
3. tsconfig と依存関係の境界の尊重
組み込みのエグゼキュータは tsconfig.json を無視するため、ターゲットの下位互換変換(target lowering)、パスのマッピング、その他のコンパイラ変換は適用されません。また、Node.js は未コンパイルのソースがパッケージの規約になるのを防ぐため、node_modules 配下の TypeScript ファイルを拒否します。変換、デコレータ、または TypeScript の依存関係が必要な場合は、完全なコンパイラまたはランタイムツールを使用してください。
4. 検証とロールバックの計画
Node バージョンのマトリックス全体で lint、型チェック、ユニットテスト、統合テスト、および起動プローブを実行します。コンパイル実行と消去実行を比較し、動作、起動時間、エラーを確認します。ランタイムを固定します。type stripping は v25.2 および v24.12 から安定しており、v26 では実験的な変換スイッチが削除されます。本番環境で問題が発生した場合は、アドホックに未サポートの変換を有効にするのではなく、コンパイル済みアーティファクトに戻します。
高品質な回答サンプル
私は組み込みの type stripping を完全なコンパイラではなく、軽量な TypeScript 実行パスとして扱います。enum、デコレータ、パラメータプロパティ、ランタイム名前空間、パスエイリアス、および TypeScript の依存関係を洗い出します。これらは変換やチェックが必要なため、コンパイラまたは tsx を維持します。移行されたコードは import type、安定したモジュールルール、および解決可能な相対パスを使用し、tsc --noEmit は型チェックのゲートとして維持されます。Node.js は tsconfig を無視するため、ビルドスクリプトでパッケージのインポートを明示的に設定する必要があります。まずは開発スクリプトや CLI からカナリアリリースし、CI で起動プローブ、ランタイムエラー、テスト、イメージの挙動を比較します。この機能は v25.2/v24.12 から安定しており、v26 では実験的な変換スイッチが削除されます。本番サービスはマトリックスを通過した後にのみ切り替え、コンパイル済みアーティファクトへのロールバック手段を保持します。
よくある間違い
- type stripping を型チェックや完全なコンパイラとして扱うこと。
- enum、デコレータ、パラメータプロパティ、またはランタイム名前空間を含むファイルを直接実行すること。
- tsconfig の paths、ターゲット変換、または JSX 設定に依存すること。
import typeを省略し、消去後に値インポートのランタイムエラーを引き起こすこと。- 本番イメージ内で
node_modulesから未コンパイルの TypeScript を実行すること。 - 型チェック、統合テスト、または古いバージョンのマトリックスなしで起動速度を測定すること。
フォローアップの質問と回答
なぜ type stripping は通常ソースマップを必要としないのですか?
この実装は注釈を空白に置き換えて文字位置を維持するため、ランタイムの行は通常ソースファイルと一致したままになります。変換された構文には、依然として完全なコンパイラとソースマップが必要です。
どのような場合に tsx やコンパイラを残す必要がありますか?
enum、デコレータ、パラメータプロパティ、パスエイリアス、ターゲット変換、完全な型チェック、またはコンパイルが必要な TypeScript の依存関係に対しては、ツールチェーンを維持してください。
Node のバージョンの違いをどのように制御しますか?
イメージ、CI、ローカルツールでバージョンを固定し、機能検出を実行します。type stripping をランタイムの前提条件として扱い、機能が存在しない場合は検証済みの JavaScript アーティファクトにフォールバックします。