首页 > 解决方案 > TypeScript:当提供变量 CLASS 作为函数参数时,将返回类型推断为该类的实例(仅来自参数)

问题描述

我想创建一个将实际类对象本身作为参数的函数(实际上是在一个充满多个参数的对象中),并且我希望将函数的返回类型推断为该类的实例,该类提供为论点。

这是一个 ORM,因此这些类是模型,每个模型都代表一个 SQL 表。然后会有许多数据库查询函数(完全在类之外),每个函数都接受参数来指示要从哪个表中选择等。

最好用代码解释...

export class DogModelClass {
    id:number;
    name:string;
    woofCount:number;
}

export class CatModelClass {
    id:number;
    name:string;
    meowCount:number;
}

interface ArgumentsInterface {
    theActualClass; // <-- this argument will be the actual CLASS itself, NOT instance of the class
}

function getModelFromDatabase(args:ArgumentsInterface) {
    // some database code to get the a "dog" or "cat" row from the DB and return an INSTANCE of the relevant args.theActualClass class
}

// I want typescript to infer that dogInstance is an INSTANCE of DogModelClass (simply from the function arguments alone)...
const dogInstance = getModelFromDatabase({theActualClass:DogModelClass});

// I want typescript to infer that catInstance is an INSTANCE of CatModelClass (simply from the function arguments alone)...
const catInstance = getModelFromDatabase({theActualClass:CatModelClass});

我知道我可以为函数本身添加一个泛型,即

function getModelFromDatabaseWithGeneric<ModelGeneric>(args:ArgumentsInterface):ModelGeneric {
    return <ModelGeneric>{};
}
const dogInstance2 = getModelFromDatabaseWithGeneric<DogModelClass>({theActualClass:DogModelClass});

但我不想在每次调用函数时都设置泛型类型,因为模型类本身已经需要在参数中设置,因为其他原因(例如函数知道要从哪个表中选择等) )。因此,每次调用所有查询函数时都必须编写两次类名,这有点多余。

我怎样才能做到这一点?

如果有更准确的术语可以用于所有这些,请告诉我。在将它们作为像这样的变量传递时,我永远不太确定在 JS 中如何调用“实际的类对象 - 而不是实例”。

标签: typescriptclassgenericstypestype-inference

解决方案


实现这一点的一种方法是将泛型类型限制为类构造函数,然后返回其InstanceType

function getModelFromDatabase<T extends { new(...args: any[]): any }>(args: { theActualClass: T }): InstanceType<T> { /* ... */ }

或者,如果您愿意,通过确保参数始终是构造函数类型:

function getModelFromDatabase<T>(args: { theActualClass: {new (...args: any[]): T} }): T { /* ... */ }

两者都实现了相同的目标:

// Infered as an INSTANCE of DogModelClass 
const dogInstance = getModelFromDatabase({theActualClass: DogModelClass});

// Infered as an INSTANCE of CatModelClass
const catInstance = getModelFromDatabase({theActualClass: CatModelClass});

推荐阅读