ecmascript-over-typescript-features について
`enum`や`namespace`などのTypeScript固有構文より、標準ECMAScriptの実行時機能を推奨するスキルです。TypeScriptの型機能を使いながら、移植性のあるJavaScriptの書き方を目指す開発者向けです。
主な機能
- 01ECMAScriptの実行時機能を優先
- 02定数オブジェクトでenumを代替
- 03namespaceの代わりにESモジュールを使用
- 04クラスプロパティを明示的に宣言
- 05型専用機能と実行時機能を区別
活用シーン
- 01enumの代替方法の選択
- 02標準モジュールによるコード整理
- 03JavaScriptとの移植性を考慮したライブラリ作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ marius-townhouse/ effective-typescript-skills --skill ecmascript-over-typescript-featuresインストール後、Claude Code で/ecmascript-over-typescript-featuresを入力して読み込まれたか確認します。
詳細
TypeScript の機能より ECMAScript の機能を優先する
概要
TypeScript には、enum や namespace のように、TypeScript 固有で JavaScript には存在しない機能があります。可能な場合は標準の ECMAScript 機能を優先してください。そちらのほうが移植性に優れ、JavaScript エコシステムで広く理解されており、TypeScript 固有のパターンに縛られずに済みます。
これは TypeScript を完全に避けるという意味ではありません。型システムは十分に活用してください。ただし、実行時の機能には標準の JavaScript を優先してください。
このスキルを使う場面
- TypeScript と ECMAScript の機能から選ぶとき
- TypeScript なしでも使える、移植性の高いコードを書くとき
- enum、namespace、パラメータープロパティを検討するとき
- 複数の JavaScript 環境を対象にするとき
- 幅広く利用されるライブラリコードを書くとき
絶対に守るルール
TypeScript 固有の実行時機能より、標準の ECMAScript 機能を優先してください。型には TypeScript、実行時の動作には JavaScript を使います。
検出
TypeScript 固有の実行時機能に注意してください。
// RED FLAGS - TypeScript-specific features
enum Status { Active, Inactive } // TypeScript enum
namespace MyLib { } // TypeScript namespace
class Foo { constructor(public x: number) {} } // Parameter properties
enum:const オブジェクトを使う
// TypeScript enum - generates runtime code
enum Status {
Active = 'ACTIVE',
Inactive = 'INACTIVE',
}
// Generates: var Status = { Active: 'ACTIVE', ... }
// BETTER: Const object with type
const Status = {
Active: 'ACTIVE',
Inactive: 'INACTIVE',
} as const;
type Status = typeof Status[keyof typeof Status];
// Status = 'ACTIVE' | 'INACTIVE'
// Usage
function setStatus(status: Status) { }
setStatus(Status.Active); // OK
setStatus('ACTIVE'); // OK
setStatus('INVALID'); // Error!
namespace:ES モジュールを使う
// TypeScript namespace
namespace Utils {
export function formatDate(d: Date): string {
return d.toISOString();
}
export const PI = 3.14159;
}
// BETTER: ES Module
// utils.ts
export function formatDate(d: Date): string {
return d.toISOString();
}
export const PI = 3.14159;
// usage.ts
import { formatDate, PI } from './utils';
パラメータープロパティ:明示的に記述する
// TypeScript parameter properties
class Person {
constructor(
public name: string,
private age: number,
protected id: string
) {}
}
// BETTER: Explicit declarations
class Person {
name: string;
private age: number;
protected id: string;
constructor(name: string, age: number, id: string) {
this.name = name;
this.age = age;
this.id = id;
}
}
TypeScript の機能を使ってよい場面
// Type-only features are fine - no runtime impact
type User = { name: string }; // TypeScript type
interface Config { } // TypeScript interface
type ID = string; // Type alias
// These compile away completely!
プレッシャーに負けないための手順
機能を選ぶときは、次の点を確認してください。
- 型だけの機能ですか? TypeScript の型は優れています
- 実行時への影響を確認する:特別なコードが生成されますか?
- 移植性を考慮する:TypeScript なしでも動作しますか?
- 標準機能を優先する:ECMAScript の機能はあらゆる環境で使えます
- 例外を文書化する:TS の機能を使わざるを得ない場合は、その理由を説明します
危険信号
| アンチパターン | 問題 | 解決策 |
|---|---|---|
文字列ユニオン型に enum を使う | TS 固有で、コードが生成される | as const オブジェクト |
namespace | TS 固有のモジュールシステム | ES モジュール |
| パラメータープロパティ | TS 固有の構文 | 明示的なプロパティ |
よくある正当化
「enum のほうが簡潔です」
実際には:as const を使った const オブジェクトなら、標準の JavaScript で同じ型安全性を実現できます。
「namespace を使うとコードを整理できます」
実際には:標準なのは ES モジュールです。ファイルと import を使ってコードを整理してください。
「パラメータープロパティなら入力の手間を省けます」
実際には:標準外の機能です。プロパティを明示的に記述したほうが、明確で移植性にも優れています。
クイックリファレンス
| 代わりに使うもの | 使うもの | 理由 |
|---|---|---|
enum | as const オブジェクト | 標準の JavaScript |
namespace | ES モジュール | 標準であり、ツリーシェイキングに優れる |
| パラメータープロパティ | 明示的なプロパティ | より明確で、標準的 |
import = | ES import | 標準のモジュールシステム |
要点
TypeScript の型システムは活用しつつ、実行時のコードには標準の ECMAScript 機能を優先してください。そうすることで、コードの移植性が高まり、より広く理解され、将来にわたって使いやすくなります。
参考資料
- Dan Vanderkam 著『Effective TypeScript』第 2 版
- 項目 72:TypeScript の機能より ECMAScript の機能を優先する