I developed a unique object factory to create instances of all my interfaces:
interface SomeInterface {
get(): string;
}
class Implementation implements SomeInterface {
constructor() {}
get() {
return "Hey :D";
}
}
type Injectable = {
[key: string]: () => unknown;
};
// deno-lint-ignore prefer-const
let DEFAULT_IMPLEMENTATIONS: Injectable = {
SomeInterface: () => new Implementation(),
};
let MOCK_IMPLEMENTATIONS: Injectable = {};
class Factory {
static getInstance(interfaceName: string, parameters: unknown = []) {
if (MOCK_IMPLEMENTATIONS[interfaceName])
return MOCK_IMPLEMENTATIONS[interfaceName]();
return DEFAULT_IMPLEMENTATIONS[interfaceName]();
}
static mockWithInstance(interfaceName: string, mock: unknown) {
MOCK_IMPLEMENTATIONS[interfaceName] = () => mock;
}
}
export const ObjectFactory = {
getInstance<T>(name: string): T {
return Factory.getInstance(name) as T;
},
mockWithInstance: Factory.mockWithInstance,
};
const impl = ObjectFactory.getInstance<SomeInterface>("SomeInterface");
This innovative Factory enables easy instantiation and mocking of interfaces. The issue lies in having to specify both the interface name and type when calling the function:
ObjectFactory.getInstance<SomeInterface>("SomeInterface")
While looking at this discussion, I found using a Base
interface not ideal. It also fails to maintain the appropriate type information.
Ideally, I envision a solution where only the interface name is required for invoking the function.
Note: Currently, the use of Injectable
is a workaround to ensure code functionality. My desired approach would involve solely the implementation name, like so:
let DEFAULT_IMPLEMENTATIONS = {
SomeInterface: Implementation
}