zhtsdi
Version:
Typescript写的依赖注入库。An dependency-injection library for TypeScript.
92 lines (74 loc) • 3.1 kB
text/typescript
/**
* Created by Weizehua on 2017/1/13.
*/
import "reflect-metadata"
interface Newable<T> extends Function {
new(...args): T;
}
@Injectable()
export class Injector {
// private static _instance = new Injector();
private static isInjectable = Symbol('Injector:is-injectable');
private static isSingleton = Symbol('Injector:is-singleton');
private static singletonInstance = Symbol('Injector:singleton-instance');
public static checkDependencyLoop = true;
public static strictDecorationCheck = true;
private constructor() {
}
static get<T>(ctor: Newable<T>): T {
// A class without @Injectable() decorated can be instantiate too
// **But that is not recommended**
if (Injector.strictDecorationCheck && !ctor[Injector.isInjectable]) {
throw new Error("To get a instance of " + ctor.name + ", you should decorate it with @Injectable().")
}
// There is a different instantiation for Singleton class.
if (ctor[Injector.isSingleton])
return ctor[Injector.singletonInstance] = ctor[Injector.singletonInstance] || Injector.create(ctor);
return Injector.create(ctor);
}
private static create<T>(ctor: Newable<T>, follwer?: Function[]): T {
let argtypes = Reflect.getMetadata("design:paramtypes", ctor) || [];
// If it depends on nothing, just new it.
if (argtypes.length === 0) {
return new ctor();
}
// If it depends on something else, check if there is a dependency loop
if (Injector.checkDependencyLoop && follwer
&& follwer.find(val => {
return val === ctor;
})) {
throw new Error("Found dependency loop while trying to instantiate " + ctor.name + ". Please check your code.");
}
// Prepare for next dependency loop check
let newFollower = (<Function[]>[ctor]).concat(follwer);
// Instantiate the arguments it needs
let args = [];
for (let i = 0; i < argtypes.length; i++) {
args.push(Injector.get(argtypes[i]), newFollower);
}
return new ctor(...args);
}
static injectableDecorator<T>(ctor: Newable<T>): Newable<T> {
ctor[Injector.isInjectable] = true;
return ctor;
}
static singletonDecorator<T>(ctor: Newable<T>): Newable<T> {
ctor[Injector.isInjectable] = true;
ctor[Injector.isSingleton] = true;
return ctor;
}
}
/* @Injectable() marks a class injectable
* Use Injector.get() to get a instance of that class
* Calling Injector.get() multiple times on a @Injectable() decorated class
* will produce different instances.
*/
export function Injectable(): ClassDecorator {
return Injector.injectableDecorator;
}
/* @Singleton() marks a singleton class.
* Use Injector.get() to get the instance of singleton class
*/
export function Singleton(): ClassDecorator {
return Injector.singletonDecorator;
}