我有一个表示数据模型的抽象类。我们叫它模特吧。它实际上是在ModelData类型中参数化的,它表示模型实际拥有的数据类型。所以:
export interface ModelData { type: string; attributes: {} }
export class Model<D extends ModelData> {}
export interface UserData extends ModelData
{ type: 'users', attributes: { name: string; }}
export class Users extends Model<UserData> {}问题是,我希望保留一个模型构造函数的存储库。当我的数据存储给我一个类似于:{ type: 'users', id: 1 }的引用列表时,我喜欢做refs.map(v => new ctors[v.type]({id: v.id}))之类的事情。
问题是,我不知道如何声明“此对象包含字符串索引的子类构造函数集。
我以前做过
private types: { [type: string]: typeof Model }然后
find<T extends ModelData>(ref: ModelReference): Model<T> {
return new types[ref.type]({id: ref.id})
}或多或少(为了简洁起见,省略了额外的空守卫和其他代码)。
这实际上是不正确的--我实际上返回的是extends Model<T>,而我在类型中存储的不是typeof Model,而是extends typeof Model。
在2.4.1之前(我认为这与隐含的泛型更改有关)编译的代码没有抱怨,尽管不正确。我很高兴把它做对了,但我不知道我怎么能用打字本来表达这个问题。
我得到的具体内容是一组ModelData类型,它为ModelData的属性和关系属性定义了不同的形状,以及一组扩展了这些ModelData类型的模型的类。因此,虽然从技术上讲,我可以返回一个模型,但我宁愿返回一个用户,因为我可能会给用户添加一些额外的方便方法。
那么,是否有可能说,“这个东西包含一个字符串索引的构造函数组,而所有这些构造函数都遵循”扩展AbstractClass“的模式?
发布于 2017-08-10 20:48:07
我建议你这样做:
const types = {
'users': Users,
// ... other Models
}
function find<K extends keyof typeof types>(ref: { type: K }): typeof types[K]['prototype'] {
return new types[ref.type](); // this only works if all Models have no-arg constructors
}如果您需要验证types是否正确,有一种方法可以使用new关键字引用某事物的构造函数:
type Constructor<T> = {
new(...args: any[]): T;
readonly prototype: T;
}如果我想说“此对象的值是适当的Model类型的构造函数,其中键与ModelData['type']值相同”,我想说:
type ModelMap<T> = {
[K in keyof T]: Constructor<Model<ModelData & { type: K }>>
}
function verifyTypes<T>(types: T, alsoTypes: ModelMap<T>) { }
verifyTypes(types, types);如果verifyTypes()给出了一个编译器错误,那是因为其中一个值是错误的:
const types = {
'user': Users
}
verifyTypes(types, types); // error: type of property 'user' is incompatible请注意,只有当您的Model类型实际保留正确的ModelData类型的某些属性时,编译器才会生气。如示例所示,如果它们是空的,那么所有类型在结构上都是相同的,编译器也不会抱怨:
export class Model<D extends ModelData> {
data: D; // that's enough
}希望这能有所帮助。祝好运!
https://stackoverflow.com/questions/45622374
复制相似问题