I am struggling to find the most elegant solution for determining the type of anonymous generic classes that are created and returned from functions.
Below is a code snippet showing the function that generates anonymous classes and one of the functions within it.
Generics are necessary for TypeScript to provide return type and parameter property hints when using the get function.
export function createController<T, U extends { id?: number }>(cls: new () => T) {
return class extends BaseController {
public constructor() {
super(cls.name.split(/(?=[A-Z])/).join('_').toLowerCase());
}
public async get(params: U): Promise<T | null> {
try {
const { data } = params.id ? await this.http.get(`${this.base}-${params.id}`) : await this.http.get('', { params });
return deserialize(cls, search(data, 'data'));
} catch (err) {
return null;
}
}
};
}
I encounter an issue when attempting to create and store the result of this procedure.
Take a look at how to create a UserController below.
export interface UserQueryParams {
id?: number;
username?: string;
}
const UserController = createController<User, UserQueryParams>(User);
Now, UserController instances can be easily created like regular classes by calling new UserController()
.
No problem arises when storing them directly like so:
// Correctly inferred as createController<User, UserQueryParams>.(Anonymous class)
const controller = new UserController();
However, if I want to create a class containing these controllers:
class Client {
public controller: ???
public constructor() {
this.controller = new UserController();
}
}
I struggle to determine the best way to type the property.
An error occurs when using
public controller: UserController
because UserController is a value and not a type.
Using
public controller: typeof UserController
also fails, as the constructor assignment becomes incompatible.
Almost there with
public controller: typeof UserController.prototype
, but the type information gets lost. It's identified as createController<any, any>.(Anonymous class)
due to the "any"s used for generics.
A workaround would be:
const temp = new UserController();
// In the class..
public controller: typeof temp;
This method works, but having to create temporary instances of every controller generated is quite messy.
Is there another way to properly type the controller
property?