Typescript 为将typeof值用于泛型类型的函数定义接口
我正在创建一个工厂,它在不丢失任何类型推断的情况下实例化一个对象 要实例化的对象类在键控集合中定义:Typescript 为将typeof值用于泛型类型的函数定义接口,typescript,Typescript,我正在创建一个工厂,它在不丢失任何类型推断的情况下实例化一个对象 要实例化的对象类在键控集合中定义: abstract class Model { } class Player extends Model { a: string; constructor(a: string) { super(); this.a = a; } say() { console.log(this.a) } } class
abstract class Model { }
class Player extends Model {
a: string;
constructor(a: string) {
super();
this.a = a;
}
say() {
console.log(this.a)
}
}
class OtherModel extends Model {}
enum ModelType {
Player,
OtherModel
}
const Models = {
[ModelType.Player]: Player,
[ModelType.OtherModel]: OtherModel
};
最后,我提出的工厂定义如下:
class ModelFactory implements IFactory {
instantiate<T extends keyof typeof Models>(type: T, ...params: ConstructorParameters<typeof Models[T]>): InstanceType<typeof Models[T]> {
if (Models) {
const ModelRef = Models[type] as new (...params: any[]) => InstanceType<typeof Models[T]>;
if (!ModelRef) {
throw new Error(`Model for '${ModelType[type]}' was not found.`);
}
return new ModelRef(...params);
}
throw new Error("No models are registered");
}
}
类ModelFactory实现IFactory{
实例化(类型:T,…参数:构造函数参数):InstanceType{
if(型号){
const ModelRef=Models[type]作为新的(…参数:any[])=>InstanceType;
如果(!ModelRef){
抛出新错误(`Model for'${ModelType[type]}'未找到。`);
}
返回新的ModelRef(…参数);
}
抛出新错误(“未注册模型”);
}
}
这非常有效,因为它能够在编译时推断构造函数属性和返回类型。我遇到的问题是为工厂定义接口。因为我得到了上面定义的模型集合类型,所以我想不出定义抽象实例化()签名的方法
我创建了一个实例来更好地说明这个问题。如果您只想让
IFactory
拥有一个实例化方法,该方法完全适用于模型
对象中的构造函数,那么您可以给它与模型工厂
中相应方法相同的签名,然后就可以完成了
假设您想要的是,对于值为构造函数的给定对象,有一个对应的实例化方法可用于该对象。如果是这样,那么您应该将IFactory
设置为一个接口,该接口取决于构造函数对象的类型。我是这样写的:
interface IFactory<M extends Record<keyof M, new (...args: any) => any>> {
instantiate<K extends keyof M>(
type: K,
...params: ConstructorParameters<M[K]>
): InstanceType<M[K]>
}
可能会声明一个不同的工厂来实现IFactory
,其中somethingElse
是一个持有不同构造函数的不同对象
还请注意,可以将整个factory类设置为通用类,如下所示:
class GenericModelFactory<
M extends Record<keyof M, new (...args: any) => any>
> implements IFactory<M> {
constructor(public models: M) {
}
instantiate<K extends keyof M>(
type: K,
...params: ConstructorParameters<M[K]>
): InstanceType<M[K]> {
const ModelRef = this.models[type] as
new (...params: ConstructorParameters<M[K]>) => InstanceType<M[K]>;
return new ModelRef(...params);
}
}
const modelFactory2 = new GenericModelFactory(Models);
const player2 = modelFactory2.instantiate(ModelType.Player, 'a', 'b');
player2.say();
class GenericModelFactory<
M扩展任何记录>
>电子工厂{
构造函数(公共模型:M){
}
实例化(
类型:K,
…参数:构造函数参数
):InstanceType{
const ModelRef=this.models[type]as
新建(…参数:构造函数参数)=>InstanceType;
返回新的ModelRef(…参数);
}
}
const modelFactory2=新的通用模型工厂(模型);
constplayer2=modelFactory2.instantiate(ModelType.Player,'a','b');
player2.说();
这将持有对象的构造函数作为工厂类本身的属性,因此您可以重用相同的工厂类,而不是为每组模型构造函数创建新的工厂类。这完全取决于你的用例,你想走哪条路
不管怎样,希望这有帮助。祝你好运
除非我有误解,否则您需要IFactory
成为泛型,然后class ModelFactory扩展IFactory
。在这种情况下,IFactory
可以定义为interface IFactory>{instantiate(type:K,…params:ConstructorParameters):InstanceType}
。这对你有用吗?如果是的话,我会写一个答案。如果没有,你能详细说明你的要求吗?祝你好运。@jcalz是的!这正是我所需要的。
class GenericModelFactory<
M extends Record<keyof M, new (...args: any) => any>
> implements IFactory<M> {
constructor(public models: M) {
}
instantiate<K extends keyof M>(
type: K,
...params: ConstructorParameters<M[K]>
): InstanceType<M[K]> {
const ModelRef = this.models[type] as
new (...params: ConstructorParameters<M[K]>) => InstanceType<M[K]>;
return new ModelRef(...params);
}
}
const modelFactory2 = new GenericModelFactory(Models);
const player2 = modelFactory2.instantiate(ModelType.Player, 'a', 'b');
player2.say();