問題の歴史:
JavaScriptのDateオブジェクトは日付と時間を表現するために使用され、その動作の特性—ミュータビリティ、パースの複雑さ、タイムゾーンの特性—で知られています。TypeScriptはDateに標準的なJSタイプを使用しますが、厳密なコードでの日時の型付けと処理には特別なアプローチが必要です。
問題:
JavaScriptのDateはミュータブルなオブジェクトであり、非典型的なエラーを引き起こす可能性があります(例えば、setMonth()はオブジェクト自体を変更し、コードの予期しない動作を引き起こす可能性があります)。さらに、外部ライブラリ(moment.js、date-fns、Day.jsなど)との統合時には型の精度を維持する必要があります—例えば、moment.Instantや互換性のない特定の時間のラッパーなどです。戻り値の型がstringまたはnumber(タイムスタンプ)になることがあるため、型注釈やAPI使用時にエラーを引き起こすことがあります。
解決策:
TypeScriptは新しいDateのインスタンスをDateとして型付けしますので、すべてのメソッドが利用可能です。他のライブラリとの統合時には、入力値と出力値の型に注意を払うことが重要です—明示的にDateにキャストする(例:new Date(value))か、日付と時間用のカスタム型コンテナを作成することが推奨されます。タイムスタンプ(number)、文字列、Dateオブジェクト間の変換には型を厳密に指定し、関数に型またはインターフェースを使用して記述する必要があります。
コード例:
function toIsoString(d: Date | number | string): string { if (d instanceof Date) return d.toISOString(); if (typeof d === 'number' || typeof d === 'string') return new Date(d).toISOString(); throw new Error('無効な日付'); }
重要な特性:
TypeScriptにおける「Date」タイプは単純なvalue typeですか?
いいえ、Dateはオブジェクトであり、すなわちreference typeです。==または===での比較は値を比較するのではなく、参照を比較します。
const d1 = new Date('2022-01-01'); const d2 = new Date('2022-01-01'); d1 === d2; // false
新しい初期化なしで、Stringや番号をDateタイプに直接割り当てることはできますか?
いいえ、Dateタイプはnumberまたはstringとは互換性がありません。新しいインスタンスを作成する必要があります:new Date(value)。
const d: Date = new Date('2020-01-01'); // const d2: Date = '2020-01-01'; // 型エラー
Dateを受け取る関数は、外部ライブラリのオブジェクト(moment、dayjs)で機能しますか?
いいえ、unlessライブラリで明示的にDateとのキャスト/互換性が実装されていない限り、これは異なるタイプであり、TypeScriptはそれをDateとして認識しません。
import dayjs from "dayjs"; function doSomething(d: Date) { /* ... */ } doSomething(dayjs()); // エラー、Dayjsの型はDateとは互換性がありません
コードで引数はanyとして受け取られ、以降はDateであると想定されました。実際にはAPIがtimestampをstringで返し、.getFullYear()を呼び出す際にエラーが発生しました。
メリット:
デメリット:
開発者はパラメータの明示的な型(Date | string | number)を作成し、type guardを導入し、関数が明示的にnew Dateを呼び出すようにしました。コンパイラはすべての型を明示的に処理することを強制します。
メリット:
デメリット: