仍在学习TypeScriptus。
我正在为Web应用程序创建模型和集合系统,我需要我的Collection
类才能实例化任何Model
子类在构造时传递的实例,例如:{{1 }}将创建new Collection<Post>()
的列表;和Post
将创建new Collection<Comment>()
的列表。
正如您将在下面粘贴的代码中看到的那样,我可以按原样执行axample,并且不会出错,但是我想从内部实例化Comment
的 any 子类Collection类不只是Model
。我该如何实现?
Post
关键所在的是// A Model attributes form API
interface Attr {
id: number;
title: string;
}
// Base model class
abstract class Model {
protected attr: Attr;
public constructor(attr: Attr) {
this.attr = attr;
}
}
// An actual model to be used in the app
class Post extends Model {
public constructor(attr: Attr) {
super(attr);
// other custom stuff, like API adapters, etc.
}
}
// A collection of Model using type T
class Collection<T extends Model> {
private collected: T[] = [];
public async fetch(): Promise<Collection<T>> {
const attrList: Attr[] = await new Promise<Attr[]>((resolve): void => {
resolve([{
id: 1,
title: 'Post 1'
}, {
id: 2,
title: 'Post 2'
}] as Attr[]);
});
this.collected = attrList.map((attr: Attr): T => {
// I can instantiate Post from here and cast it,
// but I want to use whatever is passed in T instead
return new Post(attr) as T;
})
return this;
}
public all(): T[] {
return this.collected;
}
}
const collection = new Collection<Post>();
const posts: Post[] = collection.all();
中Post
的硬编码声明,例如:Collection.fetch()
。
如何实例化有效的return new Post(attr) as T;
,例如,同时适用于T
和Post
类?
答案 0 :(得分:3)
您的Collection<T>
类实例需要保留T
的构造函数实例。
此外:对于接口使用名称Attr
可能不是一个好主意,因为已经有a type in global scope named Attr
可能是名称冲突或名称隐藏,这两种都不是特别令人愉快的事情处理。从这里开始,我将名称更改为MyAttr
。
构造Collection<T>
时,需要传入T
对象的构造函数,可以使用MyAttr
参数进行调用,并且Collection<T>
需要保持到该构造函数上以在fetch()
方法实现中使用。在Typescript中,此类构造函数的类型为new (attr: MyAttr) => T
。通过使用parameter property,我们可以简单地表示“传递并保持”操作:
class Collection<T extends Model> {
private collected: T[] = [];
public constructor(private ctor: new (attr: MyAttr) => T) {}
(如果我们想写出来,就像private ctor: new (attr: MyAttr) => T; public constructor(ctor: new (attr: MyAttr) => T) { this.ctor = ctor; }
)
然后在fetch()
方法内,我们使用this.ctor
:
public async fetch(): Promise<Collection<T>> {
const attrList = await new Promise<MyAttr[]>(
(resolve): void => {
resolve([
{
id: 1,
title: "Post 1"
},
{
id: 2,
title: "Post 2"
}
]);
}
);
this.collected = attrList.map(attr => new this.ctor(attr));
return this;
}
这应该对您有用。 (请注意,我删除了用于Promise解析的类型断言...使用内置的Attr
接口修复名称冲突后就没有必要了)
最后,当您制作collection
时,您传入了Post
构造函数。您不再需要将通用T
手动指定为Post
,因为编译器会为您推断出来:
const collection = new Collection(Post);
const posts: Post[] = collection.all();
好的,希望能有所帮助。祝你好运!
答案 1 :(得分:0)
据我所知,你做不到。
在我的应用程序上,我通过创建抽象方法getInstance()
解决了(实际上是解决方法):
abstract public getInstance(... args): T
因此,在我的普通模型上,我实现了此方法:
public getInstance(...args): Post {
return new Post(...args);
}