Menu

TypeScriptのオブジェクト型: 省略可能・readonly プロパティ

TypeScriptでオブジェクトに型を付ける方法。インラインのオブジェクト型、? による省略可能なプロパティ、readonly プロパティ、入れ子のオブジェクト、メソッド、余剰プロパティチェック、object と {} と Object の違いを解説します。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

TypeScriptのオブジェクト型は、オブジェクトが持つプロパティとそれぞれの型を並べたものです: { name: string; age: number }。プロパティを省略可能にするには ? を、再代入できないようにするには readonly を付けます。型はインラインで書くか、type や interface で名前を付けて再利用します。

オブジェクト型の書き方

プロパティは ; か , で区切ります(どちらでもよく、; が一般的です)。改行だけでも区切れます。一度しか使わないパラメーターならインラインの型でかまいませんが、2回以上使うものには名前を付けましょう。

// Inline, in a parameter
function area(rect: { width: number; height: number }): number {
    return rect.width * rect.height;
}

// Named with a type alias
type Rect = { width: number; height: number };

// Named with an interface (the same shape)
interface RectShape {
    width: number;
    height: number;
}

type と interface はどちらもオブジェクトの形を同じように表せます。違い(宣言のマージ、ユニオン)は interface と type の違い のページで説明しています。

型が宣言していないプロパティにアクセスするとコンパイルエラーです: point.z は TS2339 Property 'z' does not exist on type '{ x: number; y: number; }'. になります。

省略可能なプロパティ

名前のあとに ? を付けると、そのプロパティは省略できるようになります。省略可能なプロパティを読むと T | undefined になるので、TypeScriptは使う前に値がない場合を処理させます。

チェックせずに省略可能なプロパティのメソッドを呼ぶとエラーです: p.nickname.toUpperCase() は TS18048 'p.nickname' is possibly 'undefined'. になります。結果が undefined でもかまわない場合はオプショナルチェーン(p.nickname?.toUpperCase())を使います。

prop?: T と prop: T | undefined は同じではありません。前者はキーがなくてもよく、後者はキーが必須で、値が undefined でもかまわないという意味です:

readonly プロパティ

readonly は、オブジェクトを作ったあとでプロパティに再代入することを禁止します。これはコンパイル時だけのチェックで、しかも浅いものです。readonly プロパティに入っているオブジェクトや配列の中身は変更できます。

出力には両方の限界が表れています。id は実行時に本当に変わり(readonly だと知っていたのはコンパイラーだけです)、中の配列も変更されました。readonly の配列には readonly string[] を使い、すべてのプロパティを一度に readonly にするには Readonly<Order> を使います。

余剰プロパティチェック

オブジェクトリテラルを型付きの変数に直接代入したり、型付きのパラメーターにそのまま渡したりすると、TypeScriptは型が宣言していないプロパティを拒否します。新しく書いたリテラルの余分なプロパティは、ほとんどの場合タイプミスだからです。

index.ts(8,8): error TS2561: Object literal may only specify known properties, but 'colour' does not exist in type 'Options'. Did you mean to write 'color'?

コンパイラーが近い名前を見つけたので、エラーコードは TS2561 です。似た名前のない余分なプロパティなら TS2353 Object literal may only specify known properties, and 'z' does not exist in type 'Point'. になります。このチェックがなければタイプミスはそのままコンパイルされ、color は undefined になり、プログラムは黙って黒で描画するでしょう。チェックは新しく書いたリテラルにだけ適用されます。すでに変数に入っているオブジェクトは余分なプロパティを持っていてもかまいません。TypeScriptの型付けは構造的で、必要なプロパティを少なくとも持っていれば値は型に合うからです。

入れ子のオブジェクトとメソッド

オブジェクト型は入れ子にでき、メソッドはメソッド構文でも関数型のプロパティでも表せます。

深い形や再利用する形は、内側の型に名前を付けて(type Address = { ... })参照するか、最後の数行のように外側の型からインデックスアクセス Company["address"] で取り出します。

object と {} と Object

似た名前の3つの型は意味が違います:

型受け付ける値拒否する値
objectプリミティブ以外すべて: {}、[]、関数、クラスのインスタンス5, "a", true, null, undefined
{}null と undefined 以外のすべての値(プリミティブを含む)null, undefined
Object{} と同じ。さらに toString などの組み込みメンバーの型に互換性があるかをチェックnull, undefined
{ x: number }数値の x を持つすべての値x を持たない値

{} は「空のオブジェクト」ではなく、「null でも undefined でもない」という意味です。キーのわからない任意のオブジェクトを受け付けるには Record<string, unknown> を使います。キーから値への対応表には、辞書のページで紹介しているインデックスシグネチャか Record を使います。たいていの場合は、3つのどれよりも具体的な形を書くほうが適しています。

よくある質問

TypeScriptでオブジェクト型を定義するには?

波かっこの中にプロパティとその型を並べます: { name: string; age: number }。型注釈の中にインラインで書くことも、type User = { ... } や interface User { ... } で名前を付けて再利用することもできます。プロパティは ; か , で区切ります。

TypeScriptでプロパティを省略可能にするには?

プロパティ名のあとに ? を付けます: { name: string; nickname?: string }。オブジェクトは nickname を省略でき、読むと string | undefined になるので、文字列として使う前にチェックするかデフォルト値(user.nickname ?? user.name)を用意する必要があります。

prop?: string と prop: string | undefined の違いは何ですか?

prop?: string ではキーそのものを省略できます。prop: string | undefined ではキーが必須で、値は undefined でもかまいませんが、{} はコンパイルエラーになります。どちらも読むと string | undefined です。

TypeScriptの object、{}、Object の違いは何ですか?

object はプリミティブ以外の値(オブジェクト、配列、関数)を表し、5 や "a" は受け付けません。{} は null と undefined 以外のすべての値を表し、プリミティブも含みます。Object は {} とほぼ同じですが、toString などの組み込みメソッドの型に互換性があるかもチェックします。{} や Object ではなく object、できれば具体的な形を使いましょう。

「オブジェクトリテラルは既知のプロパティしか指定できない」と言われるのはなぜですか?

余剰プロパティチェックです。エラー TS2353、またはコンパイラーが意図したらしいプロパティを提案できる場合は TS2561 になります。新しく書いたオブジェクトリテラルを型付きの変数やパラメーターに直接代入すると、型が宣言していないプロパティはたいていタイプミスなので指摘されます。ほかの変数に入っているオブジェクトを代入する場合はチェックされません。構造的型付けでは余分なプロパティが許されるからです。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める