简体   繁体   English

TypeScript:当提供变量 CLASS 作为函数参数时,将返回类型推断为该类的实例(仅从参数中)

[英]TypeScript: when supplying a variable CLASS as a function argument, infer the return type to be an instance of that class (purely from argument alone)

I want to create a function that takes actual class objects themselves as an argument (actually in an object full of multiple arguments), and I want the return-type of the function to be inferred to be an instance of that class that was supplied as the argument.我想创建一个函数,该函数将实际的类对象本身作为参数(实际上是在一个充满多个参数的对象中),并且我希望将函数的返回类型推断为该类的一个实例,作为论点。

This is an ORM, so the classes are models which each represent an SQL table.这是一个 ORM,所以这些类是模型,每个模型都代表一个 SQL 表。 There will then be a number of database query functions (outside of the classes altogether) that each take arguments indicating what table to select from etc.然后将有许多数据库查询函数(完全在类之外),每个函数都接受指示要从哪个表中选择等的参数。

Best explained with code...最好用代码解释...

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

I know that I could add a generic to the function itself, ie我知道我可以为函数本身添加一个泛型,即

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

But I don't want to have to set the generic type the every time I call the function, as the model class itself already needs to be set in the arguments anyway for other reasons (such as the functions knowing which table to SELECT from etc).但是我不想在每次调用函数时都设置泛型类型,因为模型类本身已经需要在参数中设置,因为其他原因(例如函数知道要从中选择哪个表等) )。 So it's just kind of redundant having to write the class name twice every time I call all my querying functions.因此,每次调用所有查询函数时,必须两次编写类名是多余的。

How can I achieve this?我怎样才能做到这一点?

Also please let me know if there's more accurate terms I can use for all this.另外请让我知道是否有更准确的术语可以用于所有这些。 I'm never quite sure what to call "the actual class object - not the instance" in JS when it comes to passing them around as variables like this.当涉及到像这样将它们作为变量传递时,我从来不太确定在 JS 中调用“实际的类对象 - 而不是实例”。

One way this can be accomplished is by restricting the generic type to be a class constructor, then returning its InstanceType :可以实现的一种方法是将泛型类型限制为类构造函数,然后返回其InstanceType

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

Or, if you prefer, by ensuring the argument is always a constructor type:或者,如果您愿意,可以确保参数始终是构造函数类型:

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

Both accomplish the same goal:两者都实现了相同的目标:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM