The TypeScript typings for Map
exclusively cater to Map<K, V>
, where K
represents the key type, V
is for the value type, without any additional connection between them. Hence, using the generic Map
as-is won't enable the TypeScript compiler to impose extra constraints.
Based on the context of your inquiry, it appears that you require the key to be a (potentially abstract) constructor type and the corresponding value to be a definitively concrete constructor of a compatible type. Given that your example code solely utilizes the set()
method, the minimal typings needed to align with your specifications are:
interface MySpecialMap {
set<T extends object>(
k: abstract new (...args: any) => T,
v: new (...args: any) => T
): this;
}
interface MySpecialMapConstructor {
new(): MySpecialMap;
}
const MySpecialMap: MySpecialMapConstructor = Map;
In this representation, I've designated at runtime the MySpecialMap
constructor to mirror the Map
constructor but assigned it the type MySpecialMapConstructor
, responsible for creating instances of MySpecialMap
. The MySpecialMap
interface hosts just one method - set()
, which is generic in terms of the base class instances under type T
. The k
parameter signifies a potential abstract
constructor associated with type T
instances, while v
denotes an obligatory concrete constructor for T
instances.
Lets conduct a practical demonstration to validate its functionality:
abstract class BaseA { a() { } }
class ConcreteA1 extends BaseA { a1() { } }
class ConcreteA2 extends BaseA { a2() { } }
abstract class BaseB { b() { } }
class ConcreteB extends BaseB { b1() { } }
const map = new MySpecialMap();
map.set(BaseA, ConcreteA1); // successful
map.set(BaseA, ConcreteA2); // successful
map.set(BaseB, ConcreteB); // successful
map.set(BaseA, ConcreteB); // error
// Property 'a' is missing in type 'ConcreteB' but required in type 'BaseA'
map.set(BaseA, BaseA); // error
// Cannot assign an abstract constructor type to a non-abstract constructor type.
All seems well!
Subsequently, you may want to incorporate similar typings for get()
or any other requisite methods. Alternatively, you can adjust the call signature for set()
to specify zero-arg constructors or any other restrictions you wish to enforce. This initial setup should lay a solid foundation for you to proceed.
Interactive code demo link