Looking to create a function that can return an object instance based on a specified identifier, such as a string or symbol. The code example might appear as follows:
// defining services
type ServiceA = { foo: () => string };
const ServiceA = { foo: () => 'bar' };
type ServiceB = { bar: () => number };
const ServiceB = { bar: () => 1 };
// registering services with identifiers
registry.register('serviceA', ServiceA);
registry.register('serviceB', ServiceB);
// accessing a service by its type identifier
// crucial aspect is knowing the type!
const serviceA: ServiceA = registry.get('serviceA');
serviceA.foo();
Another key requirement is that ServiceA
and ServiceB
are not required to share an interface.
The main challenge in this scenario lies in determining the exact type of the value returned by registry.get
.
An initial attempt was made using:
enum ServiceType {
A,
B
}
const getService = (type: ServiceType): ServiceA | ServiceB => {
switch (type) {
case ServiceType.A:
return ServiceA;
case ServiceType.B:
return ServiceB;
default:
throw new TypeError('Invalid type');
}
};
A similar approach was also tried using if
, however, the compiler struggles to derive the concrete type of the returned value. When executing
const x = getService(ServiceType.A);
, the type of x ends up being ServiceA | ServiceB
, whereas the desired outcome is ServiceA
.
Is there a solution for achieving this functionality? If not, what limitations prevent this from a compiler perspective?