フロントエンド

TypeScriptのオブジェクトとは何か?型の付け方とジェネリクス

TypeScript/オブジェクトとジェネリクス

reisuta

Webエンジニア | 20代中盤 | 大学時代はGmailすら知らないIT音痴でプログラミングとは無縁の生活を送る → 独学でプログラミングを学ぶ → Web系受託開発企業にエンジニアとして就職 → Web系自社サービス企業に転職 | 実務未経験の頃からVimを愛好しており、仕事でもプライベートでも開発はVimとTmuxを使っているので、VSCodeに疎いのが最近の悩み。何だかんだでやっぱりRubyが好き。

オブジェクトとは何か?

下記の記事で紹介したプリミティブ型という基本的な7つの型以外のものを、
オブジェクトといいます。

TypeScriptプリミティブ型
参考【TypeScript基礎】プリミティブ型、基本的な型の種類について

TypeScriptの特徴は何と言っても、型にありますが、そんな型の中でも、中心的な役割を占める、プリミティブ型について、詳しく解説します。 文字ではなく、動画で観たい方は、下記をご参考ください。 h ...

続きを見る

具体的には、string、number
bigint、boolean、undefined
symbol、null以外の型のことですね。

他の言語だと、オブジェクト = クラスなどに結び付けられがちですが、
TypeScriptの場合、クラスだけにとどまらない、広い範囲を含むのが特徴です。

これは、JavaScriptやTypeScriptの大きな特徴かなと思いまして、
最初はまあまあ戸惑うかなとおもいます。

代表的なものとしては、

const val = {
    obj1: 123,
    obj2: 'hello'
}
console.log(val.obj1) // 123と表示される

こんな感じのコードがあげられます。

定義方法としては、
{}の中に、プロパティ名(キー):値と定義します。

オブジェクトの中身(プロパティ)を得ている、
console.log(val.obj1)の部分は、
プロパティアクセスに当たります。

ちなみにプロパティアクセスの方法としては、

console.log(val["obj1"]) // 123と表示される

のような記法もあります。

いくつかのデータをまとめて管理したいときなどに、
オブジェクトが利用されることが多いです。

なお、省略記法もあり、
例えば次のようにかけます。

//省略しない書き方
const hello = 'Hello World'
const user1 = {
    hello: hello,
    age: 28,
}
console.log(user1.hello)
//省略記法
const hello = 'Hello World'
const user1 = {
    hello,
    age: 28,
}
console.log(user1.hello)

変数名とプロパティ名が同じ場合、
: 変数名の部分を省略できます。

ただ、上記のような省略記法については、
何だかんだでそんなに遭遇したことがないので、
どこまで浸透しているのかは微妙なところです。

可読性という観点では、
正直どちらがいいとは断定しづらいですね。

オブジェクトの型

オブジェクトの型は、
例えば次のように記述します。

const val: { 
    obj1: number,
    obj2: string
} = {
    obj1: 123,
    obj2: 'hello'
}
console.log(val.obj1) // 123と表示される

「うん?どれが型だ?
うじゃうじゃしているな」って思った方もいるかもしれません。

この場合、変数valの型は、
{ obj1: number, obj2: string }型となります。

複数の値に対してそれぞれ型を定義しているだけで、
一つ一つについては、プリミティブのときと同様ではあります。

すなわち、上記のvalオブジェクトは、
obj1がnumberで、obj2がstringの構造をもつ、
オブジェクトだということで、
上記のような型になっています。

ただ、記述が長くなるので、
type文を使うことが実際には多いです。

type文とは、自分で
カスタムの型を宣言する文法記法のようなものです。

type valobj = {
    obj1: number,
    obj2: string
}
const val: valobj = {
    obj1: 123,
    obj2: 'hello'
}
console.log(val.obj1)

type文で宣言した型は、
上記のように型注釈に記載できます。

これだとvalの定義自体は簡潔になった感じがしますよね。

type文は、上記のように、
型を宣言する構文です

すでに存在する型に対して、
別名をつけることができます。

よくある使い方としては、
typeの宣言を別のtypesディレクトリのようなものに切り出して、
まとめて宣言して、各ファイルでそれぞれの型を呼び出すようにすると、
見通しが良くなるかなと思います。

型引数(ジェネリクス)

上記のtype文と関連して、
型引数という、type文の中でだけ有効な型として
扱えるものがあります。

type valobj<T> = {
    obj1: number,
    obj2: T
}

このような型引数を持つ型は、
ジェネリック型といいます。

上記の型を実際に使う場合は、
引数に型を指定します。

const val: valobj<string> = {
    obj1: 123,
    obj2: 'hello'
}

この場合、
stringが引数に渡されているので、
valobj型のTはstringとなり、
{ obj1: number, obj2: string }型と同様になります。

このあたりは、関数の引数と
似ていますね。

なお型引数を指定した場合、
呼び出し側で引数を指定しないと、
コンパイルエラーになります。

//型引数なしでは呼び出せない。
const val: valobj = {
    obj1: 123,
    obj2: 'hello'
}

そのため、省略可能なオプショナルな型引数にする場合は、
予めデフォルト値を定義しておく必要があります。

type valobj<T = string> = {
    obj1: number,
    obj2: T
}
const val: valobj = {
    obj1: 123,
    obj2: 'hello'
}

この場合、型引数が指定されないと、
Tはstring型になります。

配列

配列は、[]で定義される、
複数のデータをまとめたデータ構造で、
オブジェクトの一種です。

配列については、他のプログラミング言語でも
嫌というほど見ていると思うので、
イメージしやすいかと思います。

平たく言えば、複数のデータが入っている箱のような感じですね。

TypeScriptだと、下記のように配列定義します。

const arr = ['hello', 'alice', 123]
console.log(arr)

arrという変数に['hello', 'alice', 123]というものが代入されていますね。

これは、'hello'、'alice'、123の3つの値が、
arrという配列の変数に格納されている感じです。

通常の変数であれば、
一対一に対応していましたが、
オブジェクトのように、一対複数のように定義できるのが、
配列の特徴です。

配列の値にアクセスするには、

arr[0]

と番号を指定します。

0始まりからなので、先頭の要素は、
arr[0]というふうに取得します。

arr[0]だと、上記の場合、
'hello'の文字列が取得できます。

ちなみに、プログラミング言語によっては、
0ではなく、1スタートだったりすることもありますが、
基本的には0スタートの言語が多いです。

TypeScriptにおける配列は、上記の番号、
0とか1といったプロパティ名を持つ、
オブジェクトともいえるので、
実は、配列はオブジェクトの一種でもあります。

オブジェクトのプロパティアクセスの方法で
値を取得することができますもんね。

Macとマグカップの画像

プログラミング言語によっては、
上記のオブジェクトのようなデータ構造と、
配列は全く別のものだったりするので、
これもTypeScript、JavaScriptの大きな特徴ですね。

配列の型

さて、TypeScriptの特徴は型ですが、
配列の型は、

const arr: string[] = ['hello', 'alice']

というふうに、型名[]と記述します。

上記の場合、stringの要素を持つ配列とわかりますね。

もう一つの記法として、

const arr: Array<string> = ['hello', 'alice']

というのも存在します。

こちらは組み込みのジェネリック型にあたります。
(すなわち、stringというものを型引数として渡している感じですね)

どちらの記法が良いというわけではありませんが、
最初の方が、スッキリ書けるので、
私は前者の記法のほうが好きです。

ジェネリクスっぽく書きたい場合は、
後者にすると良いと思います。

また、最初に定義したような、
複数の型が混ざった配列の場合は、
ユニオン型というものを使って、

const arr: (string | number)[] = ['hello', 'alice', 123]

というふうに記述することもできます。

ユニオン型とは、上記の | の部分ですね。
stringまたはnumberという感じです。

https://typescriptbook.jp/reference/values-types-variables/union

  • この記事を書いた人
  • 最新記事

reisuta

Webエンジニア | 20代中盤 | 大学時代はGmailすら知らないIT音痴でプログラミングとは無縁の生活を送る → 独学でプログラミングを学ぶ → Web系受託開発企業にエンジニアとして就職 → Web系自社サービス企業に転職 | 実務未経験の頃からVimを愛好しており、仕事でもプライベートでも開発はVimとTmuxを使っているので、VSCodeに疎いのが最近の悩み。何だかんだでやっぱりRubyが好き。

おすすめ記事はこちら

Vim/Neovimプラグイン 1

プラグインをどれだけ入れるかは、その人の思想なども関係するので、一概にこれがいいというのはないかもしれません。 プラグインを全く入れない人もいれば、100個以上入れる人もいます。 ただそれでも、これだ ...

VimとNeovimの比較 2

本記事では、VimとNeovimの違いについて、解説します。 VimとNeovimの違いについては、普段頻繁にVimなどを使う方でなければ、正直、あまり気にしなくてもいいかなと思います。 ただ、Vim ...

Ruby変数やすべてがオブジェクトについて 3

本記事は、Rubyの基礎文法である、変数や真偽値、論理演算子に触れると同時に、「すべてがオブジェクト」というRubyの特徴的な思想についても解説します。 この思想は、Rubyの文法の根幹になっているの ...

4

エンジニアにおすすめの技術書 書籍学習は、エンジニアの嗜みみたいなところがありますが、 良書というものは、意外とそこまで多くもありません。 そこで本記事では「技術書マニアの筆者が厳選した技術書20選」 ...

5

エンジニアになるには? プログラミングは、専門性が高く自分一人で勉強するのが大変に感じることも多いですよね。 そこで本記事では「おすすめのプログラミングスクール5選」を特徴と、現役エンジニア目線で優れ ...

-フロントエンド