我有一个要以某种方式分配给类的类型,以便该类具有与所述类型相同的属性。
abstract class Model<T> {
protected options: T
constructor (options?: Partial<T>) {
this.options = { ...this.fake(), ...options }
}
abstract fake () : T
}
type UserOptions = {
userName: string,
email: string,
roles?: int[]
}
class User extends Model<UserOption> {
fake () : UserOption {
return {
userName: getRandomUsername(),
email: getRandomEmail()
}
}
}
有了这个,我能够创建新模型并实例化它们,而不必填写所有字段。任何未指定的字段只会填充随机数据。但是现在我也想直接访问这些字段,例如通过(new User()).userName
。现在,我可以公开options
并通过.options.userName
访问这些字段,但是当我需要在很多地方访问它们时,编写起来就变得很冗长。
在正确键入实例时,是否可以将所有这些属性通用地分配给实例本身?
或者,我正在考虑使用代理,然后以其他辅助方法(而不是模型本身)返回这些代理。这样,仍然需要调用方法来获取代理,但是我的其余代码将始终直接返回代理。我在abstract class Model<T>
中对此进行了尝试,但是它没有为user.proxy()
的调用者提供有关属性“存在”的任何知识(显然,由于返回类型仅为this
)。
proxy () : this {
return new Proxy(this, {
get (target, prop: keyof T, receiver) {
return target.options[prop]
}
})
}
答案 0 :(得分:1)
嗯,我不认为有一个简单且类型安全的解决方案。您希望能够制作class Model<T> extends T
或等效的mixin,但可以制作that's not legal TypeScript。您可以使用正确的 type 进行某种操作,但是如果没有assertion或两个,编译器将无法理解该对象是否属于该类型。
我要备份一秒钟。似乎对于每个Model<T>
类,您实际上都想要一个 static fake()
函数,该函数会生成默认的T
实例,对吗?那就是说,您实际上不需要从this
的实现中访问fake()
。因此,我建议不要使用new User().fake()
的形式。
如果是这样,那么您的User.fake()
构造函数将具有以下接口:
Model
然后我们可以使用一个函数,该函数可以返回给定的interface ModelConstructor<T> {
fake(): T; // static default instance maker
new(options?: Partial<T>): T; // actual constructor
}
函数:
fake()
请注意,我必须做一个断言,因为常规可调用函数不被认为可分配给构造函数(可更新)类型。 (某处存在一个GitHub问题,确切说明了为什么他们决定不允许这样做,但我现在找不到它。也许其他人知道它在哪里?)
然后您可以执行以下操作:
function makeModel<T extends object>(fake: () => T): ModelConstructor<T> {
const ret = function (this: T, options?: Partial<T>) {
Object.assign(this, fake(), options);
};
ret.fake = fake;
// this assertion or something like it is unfortunately necessary
return ret as any;
}
也许这会给您一些有关如何进行的想法。希望能有所帮助;祝你好运!