Abstract classes as injection token
Opened this issue ยท 4 comments
Abstract classes could be a neat alternative to the awkward interface issue, i.e. no need for a magic string or an additional symbol export if you can use the abstract class value as the token.
e.g. convert this:
export interface MyInterface {
value: string
}
to this:
export abstract class MyInterface {
abstract value: string
}
See example below.
Currently this doesn't actually work because "Cannot assign an abstract constructor type to a non-abstract constructor type".
Maybe the InjectionToken
type could be extended to permit abstract constructors?
// SuperService.ts
export abstract class SuperService {
abstract value: string;
// ...
}
// TestService.ts
import {SuperService} from "./SuperService";
// it's ok to implement (not extend) a class ๐
export class TestService implements SuperService {
constructor(public value: string) {}
//...
}
// Client.ts
import {injectable, inject} from "tsyringe";
import { SuperService } from "./SuperService";
@injectable()
export class Client {
// no more @inject("SuperService")
constructor(private service: SuperService) {}
}
// main.ts
import "reflect-metadata";
import {Client} from "./Client";
import {TestService} from "./TestService";
import {container} from "tsyringe";
container.register(SuperService, {
useClass: TestService
});
const client = container.resolve(Client);
// client's dependencies will have been resolved
Maybe Token could just be anything except null | undefined?
Perhaps related to #20.
@tarohi24 You're right, this does seem like a duplicate.
I'll let a team member close this in hopes it will refresh their memory first.
ISTR the problem last time I tried to implement this one could do container.register(MyAbstractClass, { useClass: MyAbstractClass });
then when you resolve the token, it actually worked (which it shouldn't). TS has come a long way since I tried that though, so there may be a way to prevent an abstract class to be put in a ClassProvider
. I may have some time to take a look at this in the next few weeks.
@MeltingMosaic Thanks for working on this issue. How about putting the type new (...args: any[]) => any;
into ClassProvider
? This type only accepts constructors of non-abstract classes.