様々なTypeScriptにおけるオブジェクトの型定義方法について

2021.10.01
様々なTypeScriptにおけるオブジェクトの型定義方法について

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!

おすすめ