TSオブジェクトのスプレッド演算子とレスト演算子の詳細な説明

TSオブジェクトのスプレッド演算子とレスト演算子の詳細な説明

概要

TypeScript 2.1 では、ES2018 で標準化されているオブジェクト スプレッド演算子と残りのプロパティ提案のサポートが追加されました。 rest 属性と spread 属性は型安全に使用できます。

オブジェクトの残り属性

3つのプロパティを持つ単純なリテラルオブジェクトが定義されていると仮定します。

const マリウス = {
  名前: 「マリウス・シュルツ」
  ウェブサイト: "https://mariusschulz.com/",
  twitterハンドル: "@mariusschulz"
};

ES6 の構造化構文を使用すると、対応するプロパティの値を保持するための複数のローカル変数を作成できます。 TypeScript は各変数の型を正しく推測します。

const { name, website, twitterHandle } = marius;

name; // 文字列型
website; // 文字列型
twitterHandle; // 文字列型

これらはすべて正しいですが、新しいものではありません。関心のあるプロパティのセットを抽出するだけでなく、... 構文を使用して残りのすべてのプロパティを REST 要素に収集することもできます。

const { twitterHandle, ...rest } = marius;

twitterHandle; // 文字列型
rest; // タイプ { name: string; website: string; }

TypeScript は、結果として得られるローカル変数の正しい型を決定します。 twitterHandle 変数はプレーンな文字列ですが、rest 変数は残りの 2 つのプロパティが構造化されていないオブジェクトです。

オブジェクトの拡張プロパティ

fetch() API を使用して HTTP リクエストを実行したいとします。これは、URL と、リクエストのカスタム設定を含むオプション オブジェクトの 2 つの引数を受け入れます。

アプリケーションでは、fetch() の呼び出しをカプセル化し、デフォルトのオプションと、特定のリクエストに対してそれらのオプションをオーバーライドする特定の設定の両方を提供できます。これらの構成項目は次のようになります。

定数デフォルトオプション = {
  メソッド: "GET",
  資格情報: 「同一オリジン」
};

const リクエストオプション = {
  メソッド: "POST",
  リダイレクト: 「フォロー」
};

オブジェクト拡張を使用すると、2 つのオブジェクトを新しいオブジェクトにマージし、fetch() メソッドに渡すことができます。

// タイプ { method: string; redirect: string; credentials: string; }
定数オプション = {
  ...デフォルトオプション、
  ...リクエストオプション
};

オブジェクト拡張プロパティは、新しいオブジェクトを作成し、defaultOptions 内のすべてのプロパティ値をコピーしてから、requestOptions 内のすべてのプロパティ値を左から右の順にコピーします。最終結果は次のようになります。

console.log(オプション);
// {
// メソッド: "POST",
// 資格情報: "同一オリジン",
// リダイレクト: "follow"
// }

割り当ての順序が重要であることに注意してください。両方のオブジェクトにプロパティが存在する場合、後で割り当てられたプロパティが、前に割り当てられたプロパティに置き換えられます。

もちろん、TypeScript はこの順序を理解します。したがって、複数の拡張オブジェクトが同じキーを持つプロパティを定義する場合、結果のオブジェクト内のそのプロパティの型は、以前に割り当てられたプロパティをオーバーライドするため、最後に割り当てられたプロパティの型になります。

obj1 は 42 です。
const obj2 = { プロパティ: "Hello World" };

const result1 = { ...obj1, ...obj2 }; // 型 { prop: string }
const result2 = { ...obj2, ...obj1 }; // 型 { prop: number }

オブジェクトの浅いコピーを作成する

オブジェクトの拡散を使用すると、オブジェクトの浅いコピーを作成できます。新しいオブジェクトを作成し、すべてのプロパティをコピーして、既存の ToDo 項目から新しい ToDo 項目を作成したいとします。これは、オブジェクトを使用すると簡単に実行できます。

定数todo = {
  テキスト:「花に水をやる」
  完了: 偽、
  タグ: ["庭"]
};

const shallowCopy = { ...todo };

実際には、すべてのプロパティ値がコピーされた新しいオブジェクトが取得されます。

console.log(todo === 浅いコピー);
// 間違い

console.log(shallowCopy);
// {
// テキスト: "花に水をやる",
// 完了: false、
// タグ: ["庭"]
// }

これで、元の ToDo 項目を変更せずにテキスト プロパティを変更できます。

hallowCopy.text = "芝を刈る";

console.log(浅いコピー);
// {
// テキスト: "芝を刈る",
// 完了: false、
// タグ: ["庭"]
// }

コンソールにログ出力します。
// {
// テキスト: "花に水をやる",
// 完了: false、
// タグ: ["庭"]
// }

ただし、新しい ToDo 項目は最初の項目と同じタグ配列を参照します。浅いコピーなので、配列を変更すると両方のtodoに影響します。

shallowCopy.tags.push("週末");

console.log(浅いコピー);
// {
// テキスト: "芝を刈る",
// 完了: false、
// タグ: ["庭", "週末"]
// }

コンソールにログ出力します。
// {
// テキスト: "花に水をやる",
// 完了: false、
// タグ: ["庭", "週末"]
// }

シリアル化されたオブジェクトのディープコピーを作成する場合は、jsON.parse(jsON.stringify(obj)) または object.assign() などの他のメソッドの使用を検討してください。オブジェクト拡張はプロパティ値のみをコピーするため、1 つの値が別のオブジェクトへの参照である場合、予期しない動作が発生する可能性があります。

keyof と lookup 型

JS は非常に動的な言語です。静的型システムで特定の操作のセマンティクスをキャプチャするのは難しい場合があります。単純な prop 関数を例に挙げます。

関数 prop(obj, key) {
  obj[キー]を返します。
}

オブジェクトとキーを受け取り、対応するプロパティの値を返します。オブジェクトの異なるプロパティは完全に異なる型を持つ可能性があり、obj がどのように見えるかさえわかりません。

では、この関数を TypeScript でどのように記述するのでしょうか?まずこれを試してください:

これら 2 つの型注釈では、obj はオブジェクトであり、key は文字列である必要があります。これで、両方のパラメータの可能な値のセットが制限されました。ただし、TS は戻り値の型を any として推論します。

定数todo = {
  id: 1,
  テキスト:「牛乳を買う」
  期限: 新しい日付(2016年11月31日)
};

const id = prop(todo, "id"); // 任意
const text = prop(todo, "text"); // 任意
const due = prop(todo, "due"); // 任意

詳細情報がないと、TypeScript は key パラメータに渡される値がわからないため、prop 関数のより具体的な戻り値の型を推測できません。これを実現するには、より多くの型情報を提供する必要があります。

keyof 演算子

プロパティ名をパラメータとして受け取る API は JS では非常に一般的ですが、これまではそれらの API に表示される型関係を表現する方法がありませんでした。

TypeScript 2.1 では、keyof 演算子が追加されました。インデックス タイプ クエリまたは keyof を入力します。インデックス タイプ クエリ keyof T によって生成されるタイプは、T の属性名です。次のような Todo インターフェースを定義したとします。

インターフェースTodo {
  id: 番号;
  テキスト: 文字列;
  期日;
}

keyof 演算子を Todo 型に適用すると、そのすべてのプロパティ キーの型 (文字列リテラル型の結合) を取得できます。

type TodoKeys = keyof Todo; // "id" | "text" | "due"

もちろん、keyof を使用する代わりに、ユニオン タイプ「id」|「text」|「due」を手動で記述することもできますが、これは面倒で、エラーが発生しやすく、保守が困難です。また、汎用的なソリューションではなく、Todo タイプ固有のソリューションである必要があります。

インデックス型クエリ

keyof を導入することで、 prop 関数の型注釈を改善できるようになりました。任意の文字列をキーパラメータとして受け入れることはもう望ましくありません。代わりに、渡されたオブジェクトの型にパラメータ キーが実際に存在する必要があります。

関数 prop<T, K は keyof T>(obj: T, key: K) を拡張します {
  obj[キー]を返す
}

TypeScript は、 prop 関数の戻り値の型を T[K] と推論するようになりました。これは、インデックス付き型検索または型検索と呼ばれます。これは、タイプ T の属性 K のタイプを表します。ここで、prop メソッドを介して以下の todo の 3 つのプロパティにアクセスすると、各プロパティの型は正しいものになります。

定数todo = {
  id: 1,
  テキスト:「牛乳を買う」
  期限: 新しい日付(2016年11月31日)
};

const id = prop(todo, "id"); // 数値
const text = prop(todo, "text"); // 文字列
const due = prop(todo, "due"); // 日付

さて、todo オブジェクトに存在しないキーを渡すとどうなるでしょうか?

コンパイラはエラーを出力しますが、これは良いことです。存在しないプロパティを読み取ろうとするのを防ぐことができるからです。

別の実際の例として、TypeScript コンパイラとともに配布される lib.es2017.object.d.ts 型宣言ファイルの Object.entries() メソッドを見てみましょう。

インターフェースObjectConstructor {
  // ...
  エントリ<T は { [key: string]: any } を拡張し、 K は keyof T>(o: T): [keyof T, T[K]][] を拡張します。
  // ...
}

エントリ メソッドはタプルの配列を返します。各タプルには属性キーと対応する値が含まれています。確かに、戻り値の型には角括弧がたくさんありますが、私たちは常に型の安全性を追求しています。

以上がTSオブジェクトスプレッド演算子とレスト演算子の詳しい説明です。TSオブジェクトスプレッド演算子とレスト演算子の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • JavaScript スプレッド演算子の使用例のまとめ [ES6 ベース]
  • ES6拡張演算子の理解と使用シナリオ
  • ES6スプレッド演算子の使用例
  • ES6拡張演算子の使い方と注意点を詳しく解説
  • ES6 拡張演算子と残り演算子の使用例の分析
  • ES6 配列拡張演算子操作例の分析
  • JS ES の新機能: 拡張演算子の紹介

<<:  Windows Server 2019 で NAS を構成する方法

>>:  MySQL マスタースレーブの原理と構成の詳細

推薦する

フロントエンドエンジニアが作ったクールなインタラクティブウェブサイトを推薦します

ウェブサイトリンク: http://strml.net/サミュエル・リード著ヒント: 昨日、Mome...

Vue2.0でデータの双方向バインディング機能をjsを使って実装する

Object.definePropertyの理解文法:オブジェクト.defineProperty(o...

Windows 10 で MySQL をダウンロードするための詳細なチュートリアル

MySQL のバージョンは、Enterprise Edition と Community Editi...

Vueプロジェクトの最適化とパッケージ化の詳細な説明

目次序文1. ルーティングの遅延読み込み1. ルートの遅延読み込みが必要なのはなぜですか? 2. ル...

MySQL 8.0.11 圧縮バージョンを Windows 10 にインストールするための詳細なチュートリアル

最近コンピュータを再インストールした後、最新バージョンのみをインストールするという強迫観念に基づいて...

Docker イメージのインポートとエクスポートのコード例

Dockerイメージのインポートとエクスポートこの記事では、移行、バックアップ、アップグレードなどの...

MySQLデータベース操作の基本コマンド

1. データベースを作成します。 データ data _name を作成します。 PHP でデータベー...

Linux インストール MongoDB の起動と一般的な問題の解決

MongoDB のインストール プロセスと問題記録1. MongoDBのインストールMongoDBを...

HTMLタグと基本要素の学習のまとめ

1. HTML の要素とタグ<br />要素は、1 つのタグまたは 1 組のタグによって...

ReactとAntdのFormコンポーネントを組み合わせてログイン機能を実装する方法を詳しく説明します

目次1. ReactとAntdを組み合わせてログイン機能を実現2. ReactとAntdを組み合わせ...

nginxとIISで使用できるSSL証明書を作成する

目次SSL証明書の作成1. 秘密鍵を生成する2. 証明書要求ファイルを生成する3. CRT証明書ファ...

モバイル端末におけるビューポートの具体的な使用法についての簡単な説明

目次1. 基本概念1.1 2種類のピクセル1.2 3つのビューポート2. ビューポート設定3. 1回...

Vue は小数点付きの星評価を実装します

この記事では、小数点付きの星評価を実装するためのVueの具体的なコードを参考までに共有します。具体的...

Windows 10 で MySql の解凍バージョンをインストールして構成する方法のチュートリアル

Windows 10 で MySql データベースの解凍バージョンをインストールするステップ 1: ...

HTMLを使用してシンプルなメールテンプレートを作成する

今日は、「ローテク」の問題について書きたいと思います。ちなみに、私は JavaScript Week...