#TypeScript オブジェクトの種類

導入

プリミティブ型に加えて、オブジェクトは JavaScript の最も基本的なデータ構造です。 TypeScript にはオブジェクト型に関する多くのルールがあります。

オブジェクトの型を宣言する最も簡単な方法は、中括弧を使用してオブジェクトを表し、中括弧内で各プロパティとメソッドの型を宣言することです。

const オブジェクト:{
  x:数値;
  y:数値;
} = { x: 1, y: 1 };

上記の例では、変数名の後にオブジェクト「obj」の型を中括弧で記述し、内部で属性名と各属性の型を宣言しています。

属性タイプはセミコロンまたはカンマで終わることができます。

//属性の型はセミコロンで終わります
タイプ MyObj = {
  x:数値;
  y:数値;
};

// 属性の型はカンマで終わります
タイプ MyObj = {
  x:数値、
  y:数値、
};

最後の属性の後には、セミコロン、カンマを記述してもしなくても構いません。

型が宣言され、オブジェクトに値が割り当てられると、指定された属性が欠落したり、冗長な属性を持つことはできません。

タイプ MyObj = {
  x:数値;
  y:数値;
};

const o1:MyObj = { x: 1 }; // エラーレポート
const o2:MyObj = { x: 1, y: 1, z: 1 }; // エラーレポート

上記の例では、変数 'o1' に属性 'y' がなく、変数 'o2' に属性 'z' がある場合、エラーが報告されます。

存在しないプロパティの読み取りと書き込みもエラーを報告します。

const オブジェクト:{
  x:数値;
  y:数値;
} = { x: 1, y: 1 };

console.log(obj.z); // エラーレポート
obj.z = 1; // エラーレポート

上記の例では、存在しない属性 z を読み書きするとエラーが発生します。

同様に、型宣言に存在する属性は削除できませんが、属性値は変更できます。

const myUser = {
  名前:「サブリナ」、
};

delete myUser.name // エラーレポート
myUser.name = "シンシア"; // 正しい

上記のステートメントでは、型宣言に存在する属性 name を削除するとエラーが発生しますが、その値は変更できます。

オブジェクトのメソッドは関数タイプを使用して記述されます。

const オブジェクト:{
  x: 数値。
  y: 数値。
  add(x:数値, y:数値): 数値;
  // または次のように記述されます
  // 追加: (x:数値, y:数値) => 数値;
} = {
  ×:1、
  y:1、
  add(x, y) {
    x + y を返します。
  }
};

上記の例では、オブジェクト obj にメソッド add() があり、そのパラメータの型と戻り値の型を定義する必要があります。

オブジェクト タイプでは、角括弧を使用してプロパティのタイプを読み取ることができます。

タイプ ユーザー = {
  名前: 文字列、
  年齢: 数字
};
type Name = ユーザー['name'] // 文字列

上記の例では、オブジェクト タイプ User は角括弧を使用して属性 name (string) のタイプを読み取ります。

TypeScript は、オブジェクト型のエイリアスを宣言できる type コマンドに加えて、オブジェクト型をインターフェイスに調整できる interface コマンドも提供します。

//書き方その1
タイプ MyObj = {
  x:数値;
  y:数値;
};

const obj:MyObj = { x: 1, y: 1 };

//書き方2
インターフェース MyObj {
  x: 数値。
  y: 数値。
}

const obj:MyObj = { x: 1, y: 1 };

上記の例では、1 つ目の記述方法は「type」コマンドを使用する方法であり、2 つ目の記述方法は「interface」コマンドを使用することです。 interface コマンドの詳細な説明および type コマンドとの違いについては、「インターフェイス」の章を参照してください。

TypeScript はオブジェクト自身のプロパティと継承されたプロパティを区別しないことに注意してください。これらはすべてオブジェクトのプロパティとみなされます。

インターフェイス MyInterface {
  toString(): string; // 継承されたプロパティ
  prop: 数値; // 独自のプロパティ
}

const obj:MyInterface = { // 正しい
  プロペラ: 123、
};

上記の例では、「obj」は「prop」属性のみを書き込みますが、エラーは報告されません。プロトタイプの toString() メソッドを継承できるためです。

オプションの属性

属性がオプションである (つまり、無視できる) 場合は、属性名の後に疑問符を追加する必要があります。

const オブジェクト: {
  x: 数値。
  y?: 数値;
} = { x: 1 };

上の例では、属性「y」はオプションです。

オプションの属性は、「未定義」への代入を許可することと同じです。次の 2 つの書き方は同じです。

タイプ ユーザー = {
  名: 文字列;
  姓?: 文字列;
};

// と同等
タイプ ユーザー = {
  名: 文字列;
  姓?: 文字列|未定義;
};

上記の例では、タイプ User のオプションのプロパティ lastName は文字列または undefined にすることができます。つまり、オプションのプロパティには unknown の値を割り当てることができます。

const オブジェクト: {
  x: 数値。
  y?: 数値;
} = { x: 1、y: 未定義 };

上の例では、オプションの属性 y に値 unknown が割り当てられており、エラーは報告されません。

同様に、値が割り当てられていないオプションのプロパティを読み取ると、「未定義」が返されます。

タイプ MyObj = {
  x: 文字列、
  y?: 文字列
};

const obj:MyObj = { x: 'こんにちは' };
obj.y.toLowerCase() // エラーレポート

上の例では、obj.yunknown を返し、それに対して toLowerCase() を呼び出すことができないため、最後の行はエラーを報告します。

したがって、オプションのプロパティを読み取る前に、それらが「未定義」かどうかを確認する必要があります。

定数ユーザー:{
  名: 文字列;
  姓?: 文字列;
} = {名: 'Foo'};

if (user.lastName !== 未定義) {
  console.log(`hello ${user.firstName} ${user.lastName}`)
}

上の例では、lastName はオプションの属性であり、使用する前にそれが 未定義 かどうかを確認する必要があります。以下のような書き方を推奨します。

//書き方その1
let firstName = (user.firstName === 未定義)
  ? 'Foo' : ユーザー名;
let lastName = (user.lastName === 未定義)
  ? 'バー' : user.lastName;

//書き方2
firstName = user.firstName ?? 'Foo';
let lastName = user.lastName ?? 'バー';

上記の例では、書き方 1 では三項演算子 ?: を使って未定義かどうかを判定し、デフォルト値を設定しています。 2 番目の書き方は Null 判定演算子 ?? を使用しており、1 番目の書き方と同じ効果があります。

TypeScript にはコンパイル設定 ExactOptionalPropertyTypes が用意されており、この設定と strictNullChecks が同時にオンになっている限り、オプションのプロパティを unknown に設定することはできません。

// ExactOptionsPropertyTypes と strictNullChecks をオンにする
const オブジェクト: {
  x: 数値。
  y?: 数値;
} = { x: 1, y: 未定義 }; // エラーレポート

上の例では、これら 2 つの設定をオンにした後は、オプションのプロパティを「未定義」に設定することはできません。

オプションのプロパティは、「未定義」に設定できる必須プロパティと同等ではないことに注意してください。

type A = { x:数値, y?:数値 };
type B = { x:数値, y:数値|未定義 };

const ObjA:A = { x: 1 }; // 正しい
const ObjB:B = { x: 1 }; // エラーレポート

上記の例では、属性 y がオプションの属性である場合は省略できますが、それが必須の属性であり unknown に設定できる場合は省略するとエラーが報告されます。 { x: 1 , y: unknown } として明示的に記述する必要があります。

読み取り専用プロパティ

readonly キーワードが属性名の前に追加され、その属性が読み取り専用属性であり、変更できないことを示します。

インターフェイス MyInterface {
  読み取り専用プロパティ: 数値;
}

上の例では、「prop」属性は読み取り専用属性であり、その値は変更できません。

定数の人:{
  読み取り専用の年齢: 数値
} = { 年齢: 20 };

person.age = 21; // エラーレポート

上記の例では、最後の行で読み取り専用属性 age が変更され、エラーが報告されます。

読み取り専用プロパティには、オブジェクトの初期化中にのみ値を割り当てることができ、その後プロパティを変更することはできません。

タイプポイント = {
  読み取り専用 x: 数値;
  読み取り専用 y: 数値;
};

const p:Point = { x: 0, y: 0 };

p.x = 100; // エラーレポート

上記の例では、タイプ Point のプロパティ xy は両方とも修飾子 readonly を持っています。これは、これら 2 つのプロパティには初期化中にのみ値を割り当てることができ、次の場合にはエラーが報告されることを意味します。それらは後で変更されます。

プロパティ値がオブジェクトの場合、「readonly」修飾子はオブジェクトのプロパティの変更を禁止するのではなく、オブジェクトの完全な置換を禁止するだけであることに注意してください。

インターフェース ホーム {
  読み取り専用常駐者: {
    名前: 文字列;
    年齢: 数字
  };
}

const h:ホーム = {
  居住者: {
    名前:「ヴィッキー」、
    年齢: 42歳
  }
};

h.resident.age = 32;
h.resident = {
  名前:「ケイト」、
  年齢: 23
} // エラーを報告する

上の例では、「h.resident」は読み取り専用プロパティであり、その値はオブジェクトです。このオブジェクトの age 属性を変更することは可能ですが、h.resident 属性全体を置き換えるとエラーが発生します。

もう 1 つ注意すべき点は、オブジェクトに 2 つの参照がある場合、つまり 2 つの変数が同じオブジェクトに対応し、1 つは書き込み可能で、もう 1 つは読み取り専用である場合、書き込み可能な変数からプロパティを変更すると読み取り専用に影響することです。変数。

インターフェイス 人 {
  名前: 文字列;
  年齢: 番号;
}

インターフェース Readonlyperson {
  読み取り専用名: 文字列;
  読み取り専用年齢: 数値;
}

w:人 = { にしてみましょう
  名前:「ヴィッキー」、
  年齢:42歳、
};

r:Readonlyperson = w; とします。

w.年齢 += 1;
レイジ // 43

上の例では、変数 wr は同じオブジェクトを指します。ここで、w は書き込み可能であり、r は読み取り専用です。次に、w のプロパティを変更すると、r に影響します。

属性値を読み取り専用にしたい場合は、宣言時に readonly キーワードを追加するほかに、値を割り当てるときにオブジェクトの後に読み取り専用アサーション as const を追加する方法もあります。

const myUser = {
  名前:「サブリナ」、
定数として;

myUser.name = "シンシア" // エラーレポート

上記の例では、読み取り専用アサーション as const がオブジェクトの後に追加されると、そのオブジェクトは読み取り専用オブジェクトになり、プロパティを変更できなくなります。

上記の「as const」は TypeScript の型推論に属することに注意してください。変数が明示的に型を宣言している場合、宣言された型に基づいて TypeScript が優先されます。

const myUser:{ 名前: 文字列 } = {
  名前:「サブリナ」、
定数として;

myUser.name = "シンシア"; // 正しい

上記の例では、変数 myUser の型宣言に従って、name は読み取り専用属性ではありませんが、値を割り当てるときに読み取り専用アサーション as const が使用されます。この時点では、name 属性は変更できるため、宣言された型が優先されます。

属性名のインデックスタイプ

オブジェクトが多数の属性を持つ場合、1 つずつ型を宣言するのは面倒です。また、外部 API から返されるオブジェクトなど、オブジェクトがいくつの属性を持つかを事前に知ることができない場合もあります。このとき、TypeScript では、「プロパティ名のインデックス型」と呼ばれる、プロパティ名式を使用して型を記述することができます。

インデックス タイプの中で最も一般的なのは、属性名の文字列インデックスです。

タイプ MyObj = {
  [プロパティ: 文字列]: 文字列
};

const obj:MyObj = {
  フー: 'a'、
  バー: 'b'、
  バズ:「ち」、
};

上記の例では、タイプ MyObj の属性名のタイプは式の形式をとり、角かっこで囲まれています。 [property: string]property はプロパティ名を表し、その型は string、つまりプロパティ名の型は string です。つまり、このオブジェクトが属性をいくつ持っていても、属性名が文字列であり、属性値も文字列である限り、このオブジェクトはこの型宣言に準拠します。

JavaScript オブジェクトのプロパティ名には 3 つのタイプがあります (つまり、上の例では property)、上の例の string に加えて、numbersymbol もあります。

タイプ T1 = {
  [プロパティ: 数値]: 文字列
};

タイプ T2 = {
  [プロパティ: シンボル]: 文字列
};

上記の例では、オブジェクト属性名の種類はそれぞれ「数字」と「記号」です。

タイプ MyArr = {
  [n:数値]: 数値;
};

const arr:MyArr = [1, 2, 3];
// または
const arr:MyArr = {
  0:1、
  1:2、
  23、
};

上記の例では、オブジェクト型 MyArr の属性名は [n:number] です。これは、その属性名がすべて 012 などの数値であることを意味します。

オブジェクトは、数値インデックスと文字列インデックスなど、複数のタイプの属性名インデックスを同時に持つことができます。ただし、数値インデックスは文字列インデックスと競合することができず、後者に従う必要があります。これは、JavaScript 言語内ではすべての数値プロパティ名が文字列プロパティ名に自動的に変換されるためです。

タイプ MyType = {
  [x: 数値]: boolean; // エラーレポート
  [x:文字列]:文字列;
}

上記の例では、型 MyType には同時に 2 つの属性名インデックスがありますが、数値インデックスが文字列インデックスと競合するため、エラーが報告されます。文字属性名の値の型は string であるため、エラーを防ぐために数値属性名の値の型も string にする必要があります。

同様に、プロパティ名のインデックスと特定の個々のプロパティ名の両方を宣言できます。 1 つの属性名が属性名インデックスの範囲と一致せず、2 つが競合する場合、エラーが報告されます。

タイプ MyType = {
  foo: boolean; // エラーレポート
  [x:文字列]:文字列;
}

上記の例では、属性名 foo は属性名の文字列インデックスと一致しますが、2 つの属性値の型が異なるため、エラーが報告されます。

属性名の宣言が広すぎて制約が少なすぎるため、属性のインデックス タイプを記述するときは注意することをお勧めします。さらに、属性名の数値インデックスを配列の宣言に使用しないでください。この方法で配列を宣言すると、さまざまな配列メソッドと length 属性が使用できなくなります。これらは、配列で定義されていないためです。タイプ。

タイプ MyArr = {
  [n:数値]: 数値;
};

const arr:MyArr = [1, 2, 3];
arr.length // エラーレポート

上記の例では、タイプ MyArr にはこのプロパティがないため、arr.length プロパティを読み取るとエラーが発生します。

代入の構造化

分割代入は、オブジェクトからプロパティを直接抽出するために使用されます。

const {ID、名前、価格} = 製品;

上記のステートメントは、オブジェクト product から 3 つの属性を抽出し、属性名と同じ名前の変数を宣言します。

代入を分割するための型の記述方法は、オブジェクトの型を宣言する場合と同じです。

const {ID、名前、価格}:{
  ID: 文字列;
  名前: 文字列;
  価格:番号
} = 製品;

JavaScript ではオブジェクトの構造化におけるコロンの他の用途が指定されているため、現時点では構造化された変数の型を指定する方法がないことに注意してください。

let { x: foo, y: bar } = obj;

// と同等
foo = obj.x にします。
バー = obj.y にします。

上の例では、コロンはプロパティ xy のタイプを示しているのではなく、これら 2 つのプロパティの新しい変数名を指定しています。 xy の型を指定したい場合は、次のように記述する必要があります。

let { x: foo, y: bar }
  : { x: 文字列; y: 数値 } = obj;

TypeScript では混乱しやすいので、これには十分注意してください。

関数描画({
  形状: 形状、
  xPos: 数値 = 100
}) {
  let myShape = 形状 // エラーレポート;
  let x = xPos; // エラーを報告します。
}

上記の例では、関数 draw() のパラメータはオブジェクトの構造化であり、内部のコロンは変数の型を指定しているように見えますが、実際には対応する属性の新しい変数名を指定しています。したがって、TypeScript は、変数 shape が関数本体に存在しないが、属性 shape の値が変数 Shape に代入されていると解釈します。

構造型の原則

オブジェクト B がオブジェクト A の構造的特徴を満たす限り、TypeScript はオブジェクト B がオブジェクト A の型と互換性があるとみなします。これは「構造的型付け」原則と呼ばれます。

タイプ A = {
  x: 数値。
};

タイプ B = {
  x: 数値。
  y:数値;
};

上の例では、オブジェクト A には、タイプ number の属性 x が 1 つだけあります。オブジェクト「B」はこの特性を満たすため、オブジェクト「A」が使用できる場合はどこでも「B」を使用できます。

const B = {
  ×:1、
  y:1
};

const A:{ x: 数値 } = B;

上記の例では、「A」と「B」は同じ型ではありませんが、「B」は「A」の構造的特徴を満たすため、「B」を「A」に割り当てることができます。

「構造型」の原則によれば、TypeScript は、値が指定された型に準拠しているかどうかをチェックするときに、値の型名 (つまり、「公称型」) をチェックするのではなく、値の構造が要件を満たしているかどうかをチェックします。 (すなわち、「構造型」)。

TypeScript は、JavaScript の動作と一致するようにこのように設計されています。 JavaScript は、オブジェクトが厳密に類似しているかどうかを気にせず、オブジェクトが必要なプロパティを持っている限り、正しく実行されます。

型 B を型 A に割り当てることができる場合、TypeScript は B を A のサブタイプ、A を B のスーパータイプとみなします。サブタイプは、親タイプの構造的特徴をすべて満たすと同時に、独自の特徴も持ちます。親タイプが使用できる場合は常に、サブタイプも使用できます。つまり、サブタイプは親タイプと互換性があります。

この設計は、場合によっては驚くべき結果をもたらす可能性があります。

type myObj = {
  x: 数値、
  y: 数値、
};

関数 getSum(obj:myObj) {
  合計 = 0 とします。

  for (const n of Object.keys(obj)) {
    const v = obj[n]; // エラー
    合計 += Math.abs(v);
  }

  合計を返します。
}

上記の例では、関数 getSum() には渡されるパラメータのタイプが myObj である必要がありますが、実際には myObj と互換性のあるすべてのオブジェクトを渡すことができます。これにより、const v = obj[n] の行でエラーが発生します。これは、obj[n] で取り出される属性値が必ずしも数値 (number) であるとは限らないためです。変数 vany として推論されます。プロジェクトが「any」への変数型推論を許可しないように設定されている場合、コードはエラーを報告します。このように書くとエラーは報告されません。

タイプ MyObj = {
  x: 数値、
  y: 数値、
};

関数 getSum(obj:MyObj) {
  戻り Math.abs(obj.x) + Math.abs(obj.y);
}

関数本体内で属性 xy のみが使用されているため、上記の例ではエラーは報告されません。これら 2 つのプロパティには明確な型宣言があり、obj.xobj.y が必ず次のように指定されている必要があります。数値。 「MyObj」と互換性のある任意のオブジェクトを関数「getSum()」に渡すことができますが、他のプロパティが使用されない限り、型エラーは報告されません。

厳密なリテラルチェック

オブジェクトがリテラルを使用して表現されている場合、TypeScript の厳密なオブジェクト リテラル チェックがトリガーされます。リテラルの構造が型定義と異なる場合 (たとえば、未定義の属性が多い場合)、エラーが報告されます。

定数点:{
  x:数値;
  y:数値;
} = {
  ×:1、
  y:1、
  z: 1 // エラーを報告する
};

上の例では、等号の右側はオブジェクト リテラルであり、厳密なリテラル チェックがトリガーされます。型宣言に存在しない属性 (この場合は z) がある限り、エラーが報告されます。

等号の右側がリテラルではなく変数である場合、構造型の原則に従って、エラーは報告されません。

const myPoint = {
  ×:1、
  y:1、
  z:1
};

定数点:{
  x:数値;
  y:数値;
} = myPoint; // 正しい。

上記の例では、等号の右側が変数の場合、厳密なリテラル チェックはトリガーされず、エラーは報告されません。

TypeScript によるリテラルの厳密なチェックの目的は、主にスペル ミスを防ぐことです。一般に、リテラルはほとんどが手書きであり、スペルミスや API の誤用が発生しやすいです。

タイプ オプション = {
  タイトル:文字列;
  ダークモード?:ブール値;
};

const obj:オプション = {
  タイトル: 「私のウェブページ」、
  ダークモード: true, // エラー
};

上の例では、属性「darkMode」のスペルが間違っており、「darkmode」になります。厳密なリテラル規則がない場合、darkMode はオプションの属性であるため、エラーは報告されません。構造型の原則によれば、オブジェクトが title 属性を持つ限り、それは ` に準拠していると見なされます。オプションのタイプ。

厳密なリテラルチェックを回避するには、中間変数を使用します。

let myOptions = {
  タイトル: 「私のウェブページ」、
  ダークモード: true、
};

const obj:Options = myOptions;

上記の例では、中間変数 myOptions が作成された場合、このときの変数 obj の割り当ては直接リテラル割り当てに属さないため、厳密なリテラル ルールはトリガーされません。

リテラルが正しいことが確実な場合は、型アサーションを使用して厳密なリテラル チェックを回避することもできます。

const obj:オプション = {
  タイトル: 「私のウェブページ」、
  ダークモード: true、
オプションとして }

上記の例では、型アサーション as Options を使用して、リテラルが Options 型に準拠していることをコンパイラーに伝え、この規則を回避しています。

リテラルに冗長な属性を持つことが許可されている場合は、次のように型に一般属性を定義できます。

x をさせます: {
  foo: 数値、
  [x:文字列]:任意
};

x = { foo: 1, baz: 2 }; // OK

上記の例では、変数 x の型宣言に属性の文字列インデックス ([x: string]) が含まれているため、任意の文字列属性名が有効になります。

厳密なリテラル チェックのため、リテラル オブジェクトは非常に慎重に関数に渡す必要があり、冗長な属性を持つことはできません。

インターフェースポイント{
  x: 数値。
  y:数値;
}

関数 computeDistance(ポイント: ポイント) { /*...*/ }

computeDistance({ x: 1, y: 2, z: 3 }); // エラーを報告します
computeDistance({x: 1, y: 2}); // 正しい

上の例では、オブジェクト リテラルが関数 computeDistance() に渡されるとき、冗長な属性を持つことはできません。冗長な属性を持つと、厳密なリテラル チェックに失敗します。

コンパイラ オプション suppressExcessPropertyErrors を使用すると、冗長なプロパティ チェックをオフにすることができます。 tsconfig.json ファイルには次のように記述されます。

{
  "コンパイラーオプション": {
    "suppressExcessPropertyErrors": true
  }
}

最小限のオプション属性ルール

「構造型」の原則によれば、オブジェクトのすべてのプロパティがオプションの場合、他のオブジェクトもそれと同様の構造を持つことになります。

タイプ オプション = {
  ?:数字;
  b?:数値;
  c?:数値;
};

上記の例では、タイプ Options のすべてのプロパティはオプションであるため、空のオブジェクトにすることができます。これは、任意のオブジェクトが Options の構造を満たすことを意味します。

これを回避するために、TypeScript 2.4 では、[「弱い型チェック」] (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4. html#weak-type-detection)(弱い型の検出)。

タイプ オプション = {
  ?:数字;
  b?:数値;
  c?:数値;
};

const opts = { d: 123 };

const obj:Options = opts; // エラーレポート

上の例では、オブジェクト opts と型 Options には共通の属性がなく、この型の変数に割り当てられるとエラーが報告されます。

エラーの理由は、特定のタイプのすべての属性がオプションの場合、そのタイプのオブジェクトに少なくとも 1 つのオプション属性が存在する必要があり、すべてのオプション属性が存在することはできないためです。これを「最小オプション属性ルール」と呼びます。

このルールを回避したい場合は、型にインデックス プロパティを追加するか ([propName: string]: someType)、または型アサーション (opts as Options) を使用します。

空のオブジェクト

空のオブジェクトは、TypeScript の特別な値であり、特別な型です。

const obj = {};
obj.prop = 123; // エラーレポート

上記の例では、変数 obj の値は空のオブジェクトであるため、値を obj.prop に割り当てるときにエラーが報告されます。

その理由は、この時点で TypeScript は変数 obj の型が空のオブジェクトであると推測し、実際に次のコードが実行されるためです。

const obj:{} = {};

空のオブジェクトにはカスタム プロパティがないため、カスタム プロパティに値を割り当てるとエラーが発生します。空のオブジェクトは、継承されたプロパティ、つまりプロトタイプ オブジェクト Object.prototype から継承されたプロパティのみを使用できます。

obj.toString() // 正しい

上記の例では、toString() メソッドはプロトタイプ オブジェクトから継承されたメソッドであり、TypeScript では空のオブジェクトでも使用できます。

このセクションの冒頭の例に戻ると、JavaScript ではこの書き方が実際に非常に一般的です。最初に空のオブジェクトを宣言し、次に空のオブジェクトにプロパティを追加します。ただし、TypeScript ではプロパティを動的に追加できないため、オブジェクトを段階的に生成することはできず、生成時にすべてのプロパティを一度に宣言する必要があります。

// 間違い
const pt = {};
pt.x = 3;
pt.y = 4;

// 正しい
const pt = {
  ×:3、
  y: 4
};

本当に段階的に宣言する必要がある場合は、スプレッド演算子 (...) を使用して新しいオブジェクトを合成する方が良い方法です。

const pt0 = {};
const pt1 = { x: 3 };
const pt2 = { y: 4 };

const pt = {
  ...pt0、...pt1、...pt2
};

上記の例では、オブジェクト pt は 3 つの部分で構成されており、これらは段階的に宣言でき、TypeScript の静的宣言の要件も満たしています。

型としての空のオブジェクトは、実際には Object 型の略称です。

let d:{};
// と同等
// d:Object にしてみましょう。

d = {};
d = { x: 1 };
d = 'こんにちは';
d = 2;

上記の例では、さまざまな型の値 (nullunknown を除く) を空のオブジェクト型に割り当てることができ、これは Object 型と同じように動作します。

Object はさまざまな型の値を受け入れることができ、空のオブジェクトは Object 型の略称であるため、厳密なリテラル チェックは行われず、値を割り当てるときに冗長なプロパティは常に許可されますが、これらのプロパティは読む。

インターフェースが空の { }
const b:Empty = {myProp: 1, anotherProp: 2}; // 正しい
b.myProp // エラーレポート

上記の例では、変数 b の型は空のオブジェクトであり、これは Object 型とみなされます。厳密なリテラル チェックは行われませんが、追加の属性を読み取るときにエラーが報告されます。

属性のないオブジェクトを強制的に使用したい場合は、次のような書き方が可能です。

インターフェイス WithoutProperties {
  [キー: 文字列]: 決して;
}

// エラーを報告する
const a:WithoutProperties = { prop: 1 };

上記の例では、[key: string]:never は文字列属性名が存在しないことを意味するため、他のオブジェクトが割り当てられるとエラーが報告されます。


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0