TypeScript: при предоставлении переменной CLASS в качестве аргумента функции, выведите тип возвращаемого значения как экземпляр этого класса (исключительно из одного аргумента) - PullRequest
1 голос
/ 22 февраля 2020

Я хочу создать функцию, которая принимает фактические объекты класса в качестве аргумента (фактически в объекте, полном множественных аргументов), и я хочу, чтобы возвращаемый тип функции был выведен как экземпляр этого класса, который был предоставлен в качестве аргумента.

Это ORM, поэтому классы являются моделями, каждый из которых представляет таблицу SQL. Затем будет несколько функций запросов к базе данных (вне классов), каждая из которых принимает аргументы, указывающие, какую таблицу выбрать из et c.

Лучше всего объяснить с помощью кода ...

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

Я знаю, что мог бы добавить generic c к самой функции, то есть

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

Но я не хочу устанавливать тип generic c каждый раз, когда я вызовите функцию, так как сам класс модели уже должен быть установлен в аргументах в любом случае по другим причинам (например, функциям, знающим, какую таблицу ВЫБРАТЬ из et c). Так что это просто излишне - писать имя класса дважды каждый раз, когда я вызываю все свои функции запросов.

Как мне этого добиться?

Также, пожалуйста, дайте мне знать, если есть более точные термины Я могу использовать для всего этого. Я никогда не совсем уверен, как назвать «фактический объект класса, а не экземпляр» в JS, когда дело доходит до передачи их в виде переменных, подобных этой.

1 Ответ

1 голос
/ 22 февраля 2020

Один из способов добиться этого - ограничить тип generi c конструктором класса, а затем вернуть его InstanceType:

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

Или, если хотите, обеспечить аргумент всегда является конструктором типа:

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

Оба достигнуты sh одна и та же цель:

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

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