儿童的模型/收藏打字稿打字

时间:2020-09-28 22:58:27

标签: typescript typescript-typings

我尝试通过各种类型的输入来处理模型/集合模式,但是我陷入了困境。简而言之,模型和集合都具有serialize()方法。在Collection上调用序列化方法将序列化所有Model。

这里是Typescript Playground that's I've been working on

/**
 * MODEL
 */
interface SerializedModel {
  type: string;
}

interface ModelInterface {
  serialize(): SerializedModel;
}

/**
 * MODEL: Contact
 */
interface SerializedContact extends SerializedModel {
  name: string;
}

class Contact implements ModelInterface {
  public name: string;

  public constructor(name: string) {
    this.name = name;
  }

  public serialize(): SerializedContact {
    return {
      type: "Contact",
      name: this.name,
    };
  }
}
/**
 * COLLECTION
 */

interface SerializedCollection<M> {
  count: number;
  items: { serialize(): M };
}

interface CollectionInterface<I> {
  count: number;
  items: I;

  serialize(): SerializedCollection<I>;
}

class Collection implements CollectionInterface<ModelInterface[]> {
  public count: number;
  public items: ModelInterface[];

  public constructor(items: ModelInterface[], count: number) {
    this.items = items;
    this.count = count;
  }

  public serialize(): SerializedCollection<ModelInterface[]> {
    return {
      count: this.count,
      items: this.items.map((item) => item.serialize()),
    };
  }
}
/**
 * TESTING
 */

// This is where I'm stuck.  I feel like I need to do something like this...
const contactCollection = new Collection<Contact>(
  [new Contact("Bill"), new Contact("Bob")],
  2
);

const serializedContactCollection = contactCollection.serialize();

serializedContactCollection.items.forEach((contact) => {
  console.log(`User's name is ${contact.name}`)
});


修订:Playground link

1 个答案:

答案 0 :(得分:0)

我找到了三种方法来执行此操作,具体取决于您是否要在ERROR in Cannot read property 'members' of undefined 中保留特定ModelInterface的类型信息以及您想要的CollectionInterface的类型参数成为。

首先,让我们修复CollectionInterfaceModelInterface的类型,它们应该使用generic constraints

SerializedCollection

选项1:// A type that can serialize into a M, which must be a SerializedModel interface ModelInterface<M extends SerializedModel> { serialize(): M; } // Contact can serialize into SerializedContact class Contact implements ModelInterface<SerializedContact> { /* ... */ } // A serialized collection of Ms interface SerializedCollection<M extends SerializedModel> { count: number; // I believe this is what you want (instead of { serialize(): M }) items: M[]; } 的单独类型参数

这样,您可以将特定ModelInterface的类型信息保留在ModelInterface中。但是,我无法正确进行类型推断。在构造CollectionInterface时,您需要明确声明类型参数。

下面Collection的代码也使用了parameter properties,这只是做Collection之类的更方便的方式。

class C { public x: number; constructor(x: number) { this.x = x } }

Playground link


选项2:仅知道// A type that can serialize into a collection of Ms from the serializable Is interface CollectionInterface<M extends SerializedModel, I extends ModelInterface<M>> { count: number; items: I[]; serialize(): SerializedCollection<M>; } // A class that implements CollectionInterface for a model M and model interface I class Collection<M extends SerializedModel, I extends ModelInterface<M>> implements CollectionInterface<M, I> { constructor(public items: I[], public count: number) {} public serialize(): SerializedCollection<M> { /* ... */ } } // If you don't specify the type parameters TS will infer contactCollection to be // Collection<SerializedModel, Contact> for some reason const contactCollection = new Collection<SerializedContact, Contact>( [new Contact("Bill"), new Contact("Bob")], 2 ); // type Contact[] const contacts = contactCollection.items; 的{​​{1}}是CollectionInterface

这种方式的好处是不需要指定类型参数。但是,如果您需要知道下面的itemsModelInterface<M>而不仅仅是contacts,则需要使用选项1。

Contact[]

Playground link


选项3:使用ModelInterface<SerializedContact>[]作为// A type that can serialize into a collection of Ms interface CollectionInterface<M extends SerializedModel> { count: number; items: ModelInterface<M>[]; serialize(): SerializedCollection<M>; } // A class that implements CollectionInterface for a model M class Collection<M extends SerializedModel> implements CollectionInterface<M> { constructor(public items: ModelInterface<M>[], public count: number) {} public serialize(): SerializedCollection<M> { /* ... */ } } // type Collection<SerializedContact> const contactCollection = new Collection( [new Contact("Bill"), new Contact("Bob")], 2 ); // type ModelInterface<SerializedContact>[] const contacts = contactCollection.items; 的类型参数

这类似于选项1,因为保留了特定ModelInterface的类型信息,但是不需要像选项2一样指定类型参数。但是,它需要{{1 }}的CollectionInterface

ModelInterface

Playground link


序列化集合后,所有这些选项的工作方式都相同:

Collection