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

Posted

技术标签:

【中文标题】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) 【发布时间】:2020-06-06 16:10:37 【问题描述】:

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

这是一个 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 中如何调用“实际的类对象 - 而不是实例”。

【问题讨论】:

【参考方案1】:

实现这一点的一种方法是将泛型类型限制为类构造函数,然后返回其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);

【讨论】:

谢谢你,对我很有用!两者都非常适合我正在尝试做的事情。后续问题:我只是好奇为什么它包含any[] ...方括号暗示某处涉及到一个数组,但我想不出数组是如何相关的? any[] 是构造函数类型签名的一部分,代表它的参数。由于带参数的类构造函数不能分配给不带参数的构造函数,因此我们允许使用 ...args: any[] 语法的任意数量的任意参数。如果你不喜欢any,那么在它的位置使用unknown 可以获得相同的结果。详情请见here。

以上是关于TypeScript:当提供变量 CLASS 作为函数参数时,将返回类型推断为该类的实例(仅来自参数)的主要内容,如果未能解决你的问题,请参考以下文章

vue-class-component + typescript:如何在导入的函数中使用组件的类作为“this”的类型?

应由服务提供的 Typescript Angular 访问参数

Typescript:环境变量的类型 Guard 作为 JSON 对象的键

TypeScript 学习笔记 — 类型推断和类型保护

如何在 TypeScript 中将函数作为变量调用 [关闭]

初探TypeScript