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();