歴史的背景:
Symbol型は、JavaScript(ES6)で導入されており、オブジェクトの他のプロパティと衝突することが保証されないユニークな識別子を作成するためのものです。TypeScriptはES6互換性が導入されたとき以来、シンボルをサポートしています。
問題点:
シンボルが登場する前は、オブジェクトのプロパティのキーとしては文字列が頻繁に使用されていました。これは、オブジェクトを拡張または再利用する際にエラーを引き起こす原因となることがありました:名前の衝突や、プライベートプロパティを隠すことができない(慣習による隠蔽も含む)問題です。シンボルにより、外部コードから見えないユニークなキーを作成することができるようになりましたが、型付けに対する疑問—シンボルキーの型をどのように記述し、APIで安全に使用するか—が生じました。
解決策:
TypeScriptはシンボルを値および型としてサポートしますが、シンボルキーの型付けには特有の特徴があります。シンボルを作成するためには、グローバルコンストラクタまたはグローバルシンボルレジストリを使用できます。インターフェースや型の中で、シンボルのキーは明示的に型をsymbolとして示す必要があり、そのプロパティへのアクセスはシンボルへの保存された参照を介してのみ行えます。
コード例:
const SECRET = Symbol('secret'); interface SecretObject { [SECRET]: string; visible: string; } const obj: SecretObject = { visible: 'see me', [SECRET]: 'hidden', }; console.log(obj.visible); // 'see me' // console.log(obj["secret"]); // エラー:そのプロパティは存在しません! console.log(obj[SECRET]); // 'hidden'
主な特徴:
シンボルはオブジェクトで使用されると自動的に文字列に変換されることがありますか?
いいえ、シンボルは自動的に文字列に変換されることはなく、それを試みる(たとえば、連結を通じて)とエラーが発生します。
const mySymbol = Symbol('desc'); // alert('prefix_' + mySymbol); // TypeError
Object.keysを使用してシンボルキーを列挙できますか?
いいえ、Object.keysとfor...inはシンボルキーを無視します。これらのキーを取得するにはObject.getOwnPropertySymbolsを使用します。
const sym = Symbol('a'); const obj = { [sym]: 42 }; Object.keys(obj); // [] Object.getOwnPropertySymbols(obj); // [Symbol(a)]
Object.assignを通じてシンボルキーのプロパティはコピーされますか?
はい、Object.assignは文字列キーとシンボルキーの両方をコピーします。これに対してJSON.stringifyはそうではありません。
const s = Symbol('s'); const o1 = { [s]: 123, foo: 'bar' }; const o2 = Object.assign({}, o1); o2[s]; // 123
開発者はプライベートプロパティに文字列キー('_private')を使用し、慣習に従っていました。チームBが偶然に同じ文字列を追加した場合、プロパティが衝突し、予測不可能なエラーが発生しました。
利点:
欠点:
別の開発者は隠しプロパティのためにシンボルを使用しました(たとえば、Symbol('internal'))。これにより、チーム内で偶然に内部データを上書きすることはできません:特定のシンボルへの参照が必要です。
利点:
欠点: