Mapped Types
インデックス型では設定時はどのようなキーも自由に設定できてしまい、アクセス時は毎回undefined
かどうかの型チェックが必要です。入力の形式が決まっているのであればMapped Typesの使用を検討できます。
Mapped Typesは主にユニオン型と組み合わせて使います。先ほどシステムがサポートする言語を定義しました。
ts
typeSystemSupportLanguage = "en" | "fr" | "it" | "es";
ts
typeSystemSupportLanguage = "en" | "fr" | "it" | "es";
これをインデックス型と同じようにキーの制約として使用することができます。
ts
typeButterfly = {[key inSystemSupportLanguage ]: string;};
ts
typeButterfly = {[key inSystemSupportLanguage ]: string;};
このようにButterfly
を定義するとシステムがサポートしない言語、ここではde
が設定、使用できなくなります。
ts
constbutterflies :Butterfly = {en : "Butterfly",fr : "Papillon",it : "Farfalla",es : "Mariposa",Type '{ en: string; fr: string; it: string; es: string; de: string; }' is not assignable to type 'Butterfly'. Object literal may only specify known properties, and 'de' does not exist in type 'Butterfly'.2322Type '{ en: string; fr: string; it: string; es: string; de: string; }' is not assignable to type 'Butterfly'. Object literal may only specify known properties, and 'de' does not exist in type 'Butterfly'.: "Schmetterling", de };
ts
constbutterflies :Butterfly = {en : "Butterfly",fr : "Papillon",it : "Farfalla",es : "Mariposa",Type '{ en: string; fr: string; it: string; es: string; de: string; }' is not assignable to type 'Butterfly'. Object literal may only specify known properties, and 'de' does not exist in type 'Butterfly'.2322Type '{ en: string; fr: string; it: string; es: string; de: string; }' is not assignable to type 'Butterfly'. Object literal may only specify known properties, and 'de' does not exist in type 'Butterfly'.: "Schmetterling", de };
プロパティを読み取り専用にするreadonly
をそのオブジェクトのすべてのプロパティに適用するReadonly<T>
というユーティリティ型があります。他にもユーティリティ型はありますが、それらについては専門のページがありますのでここでは割愛します。
📄️ Readonly<T>
全プロパティを読み取り専用にする
Readonly<T>
もこの機能で実現されています。Readonly<T>
は次のように実装されています。
ts
typeReadonly <T > = {readonly [P in keyofT ]:T [P ];};
ts
typeReadonly <T > = {readonly [P in keyofT ]:T [P ];};
keyof T
という見慣れない表現が登場しましたが、これはオブジェクトのキーをユニオン型に変更するものだと解釈してください。keyof
の詳細は型演算子をご覧ください。
📄️ keyof型演算子
keyofはオブジェクトの型からプロパティ名を型として返す型演算子です。たとえば、nameプロパティを持つ型に対して、keyofを使うと文字列リテラル型の"name"が得られます。
Mapped Typesには追加のプロパティが書けない
Mapped Typesは追加のプロパティが定義できません。ここは、インデックス型とは異なる点です。
ts
typeKeyValuesAndName = {[K in string]: string;A mapped type may not declare properties or methods.7061A mapped type may not declare properties or methods.: string; // 追加のプロパティ name };
ts
typeKeyValuesAndName = {[K in string]: string;A mapped type may not declare properties or methods.7061A mapped type may not declare properties or methods.: string; // 追加のプロパティ name };
追加のプロパティがある場合は、その部分をオブジェクトの型として定義し、Mapped Typesとインターセクション型を成す必要があります。
ts
typeKeyValues = {[K in string]: string;};typeName = {name : string; // 追加のプロパティ};typeKeyValuesAndName =KeyValues &Name ;
ts
typeKeyValues = {[K in string]: string;};typeName = {name : string; // 追加のプロパティ};typeKeyValuesAndName =KeyValues &Name ;
上の例は、ひとつの型にまとめることもできます。
ts
typeKeyValuesAndName = {[K in string]: string;} & {name : string; // 追加のプロパティ};
ts
typeKeyValuesAndName = {[K in string]: string;} & {name : string; // 追加のプロパティ};