Typescript:インターフェイスパラメータを取得するときにオプションのプロパティに名前を付ける/構造を解除するだけですか?

1
2022.01.13

私はTypeScriptの初心者で、私のプロジェクトのために非常にシンプルなORMとして働くためにいくつかのクラスを書いています。私は、パラメータがインターフェイスに準拠することを要求する方法を学びました。

interface UserInfo {
    userId: string
    email?: string
    // many more properties...
}
class User {
    constructor(connection: typeof db, init: UserInfo) {
    // code here

そして、私はこれらのオプションのプロパティのデフォルト値を設定する構文は次のものであることを理解しています:

class User {
    constructor(connection: typeof db, {email = null, /*...*/}: UserInfo) {
    // code here

しかし、 私のUserInfo インターフェイスは長いですが、このオブジェクトのコンストラクタのパラメータに巨大なオブジェクトを入力せずに、プロパティの一部を指定/デフォルトにしたい場合はどうでしょうか?インターフェイス全体を必要とするが、一部のプロパティのみを構造解除する方法はありますか?

回答
3
2022.01.14

デストラクター は、明示的に言及していないプロパティを本質的に無視するので、実際には大きな適合ではありません。言及されていないプロパティを見失わないように 、rest オブジェクトに分解することができます。

class User {
  constructor({ email = "xyz", ...rest }: UserInfo) {}
}

しかし、emailという名前の変数が、string値を持つ変数に渡された値またはデフォルトの "xyz" (nullではなく) です。nullは、渡された でない場合はstring)ではありません。また、restという名前の変数にOmit<UserInfo, "email">値が含まれることもあります (一部のプロパティ キーを忘れるために型を広げた場合の動作を表すためにOmit<T, K>ユーティリティの型を使用しています)。

Required<UserInfo>型の値が実際に必要な場合(Required<T>ユーティリティの型を使用して、必要なオプションのプロパティを変更した型を表しています)、オブジェクトの展開と共にオブジェクト リテラルの短縮プロパティ名を使用するなど、これらの部分から再アセンブルする必要があります。

class User {
  userInfo: Required<UserInfo>
  constructor({ email = "xyz", ...rest }: UserInfo) { // <-- split it apart       
    this.userInfo = { email, ...rest }; // <-- put it back together
  }
}

それはうまくいくが、それは不必要に破壊的である(あなたがパンを許すならば)。


代わりに、広がり込みだけで同じ効果を得ることができます。

class User {
  userInfo: Required<UserInfo>
  constructor(init: UserInfo) {
    this.userInfo = { email: "xyz", ...init };
  }
}

渡されたコンストラクタ引数に email プロパティがない場合 、"xyz" のデフォルトの引数が存在します。それ以外の場合、引数の email プロパティは既定値を上書きします。


とにかくどちらの場合も、それが望どおりに動作することを確認することができます:

const u = new User({ userId: "abc" });
console.log(u.userInfo.userId) // abc
console.log(u.userInfo.email) // xyz

const v = new User({ userId: "def", email: "ghi" });
console.log(v.userInfo.userId) // def
console.log(v.userInfo.email) // ghi

コードへの遊び場リンク