TypeScriptでは型を定義する事で様々な恩恵を受ける事が出来ます。
その中でもオブジェクトの型定義の方法を私の場合良く忘れてしまう..😅w
そのため、備忘録も兼ねてまとめます。
新たな書き方やいい書き方があれば追記・編集していきます。
検証した環境
1 | typescript | 4.3.5 |
オブジェクトの型定義の基本形
{key: value}
を [key: string]: string
のように定義します
const fruits: { [key: string]: string } = { apple: 'りんご', orange: 'オレンジ' }
ユニオン型(Union Type)を使ってvalueを表現する事も可能
TypeScriptの型システム - Union Type - TypeScript Deep Dive 日本語版
const fruits: { [key: string]: string | number } = { apple: 'りんご', orange: 'オレンジ', grape: 3 }
Recordを使う
TypeScriptには組み込み関数(Utility Types
)と呼ばれるものがあり、
TypeScript: Documentation - Utility Types
その中の1つのRecord
を使う事で同じように表現をする事が出来ます
TypeScript: Documentation - Record
const fruits: Record<string, string | number> = { apple: 'りんご', orange: 'オレンジ', grape: 3 }
組み込み関数は import
不要です
文字列リテラルと組み合わせる
TypeScriptで良く利用する文字列リテラル
リテラル型 - TypeScript Deep Dive 日本語版
// 文字列リテラル型(string literal)
type SnsType = 'twitter' | 'facebook' | 'google'
先ほどの基本形と同じように書くとエラーが起きます
type SnsType = 'twitter' | 'facebook' | 'google'
const SnsUrls: { [key: SnsType]: string } = {
twitter: 'https://twitter.com/',
facebook: 'https://www.facebook.com',
google: 'https://google.com',
}
// => TS1337:
// An index signature parameter type cannot be a union type.
// Consider using a mapped object type instead.
対応するには in
を使ったMapped Types
を利用します
TypeScript: Documentation - Mapped Types
type SnsType = 'twitter' | 'facebook' | 'google'
// [key in SnsType] (Mapped Types)を使用する
const SnsUrls: { [key in SnsType]: string } = {
twitter: 'https://twitter.com/',
facebook: 'https://www.facebook.com',
google: 'https://google.com',
}
また、ここでもRecord
を使えます
書き方が基本形と同じだからこっちの方が分かりやすいかな?
const SnsUrls: Record<SnsType, string> = {
twitter: 'https://twitter.com/',
facebook: 'https://www.facebook.com',
google: 'https://google.com',
}
全てを定義しない場合
注意点として↑の書き方の場合、
SnsType
で定義した3つ全てをSnsUrls
でも定義しないと怒られます
const SnsUrls: { [key in SnsType]: string } = {
twitter: 'https://twitter.com/',
}
// => TS2739:
// Type '{ twitter: string; }' is missing the following properties
// from type '{ twitter: string; facebook: string; google: string; }': facebook, google
「facebook と google が定義されてないよ」と怒られていますね
全部定義しなくていい場合は?
を使ったOptional Property
を使って解決出来ます
TypeScript: Documentation - Optional Property - Object Types
const SnsUrls: { [key in SnsType]?: string } = {
twitter: 'https://twitter.com/',
}
// => OK!
ただし Record
を使う場合は?
を使えません 😅
むー、ややこしい
Recordを使う場合は、同じくTypeScriptの組み込み関数Partial
を使います
// 構文エラー に
const SnsUrls: Record<SnsType?, string> = {
twitter: 'https://twitter.com/',
}
// [key in SnsType]? と同じ挙動に
const SnsUrls: Partial<Record<SnsType, string>> = {
twitter: 'https://twitter.com/',
}
// => OK!