One issue to address is the excessive number of generic type parameters in your code. The constraint
T extends Readonly<Record<string, Ctor>>
does not provide an inference site for
Ctor
, and similarly, the constraint
Ctor extends new (...args: unknown[]) => Inst
fails to serve as an inference site for
Inst
. As a result, inference for
Ctor
and
Inst
will fall back on the constraints provided. Your code can be simplified to:
class Registry<T extends Readonly<Record<string, new (...args: unknown[]) => unknown>>> {}
To improve this, consider modifying it like so:
class Registry<T extends { [K in keyof T]: new () => object }> { }
This adjustment eliminates unnecessary complexity such as the use of Readonly
or allowing arbitrary constructor arguments.
The main challenge arises when trying to interpret new ctor()
within the context of the generic type T[K]
. The compiler struggles to understand how to handle this generically without explicit guidance. One way to address this is by utilizing type assertions:
class Registry<T extends { [K in keyof T]: new () => object }> {
constructor(public records: T) { }
getCtor<K extends keyof T>(key: K) {
return this.records[key]
}
getInst<K extends keyof T>(key: K) {
const ctor = this.records[key]
return new ctor() as InstanceType<T[K]> // assert
}
}
While effective, this method requires manual verification of types rather than relying solely on the compiler.
A more efficient approach involves making the class generic based on the object of instance types rather than the type of records
. By doing so, you simplify the structure and enhance readability using mapped types:
class Registry<T extends { [K in keyof T]: object }> {
constructor(public records: { [K in keyof T]: new () => T[K] }) { }
getCtor<K extends keyof T>(key: K) {
return this.records[key]
}
getInst<K extends keyof T>(key: K) {
const ctor = this.records[key]
return new ctor();
}
}
This modification allows for a clearer distinction between functions like getCtor()
and getInst()
, providing a smoother workflow within your codebase.
Code Playground Link