中间唯一用到reflect-matadata类
hasKey函数,在ts中需要这个函数加强ts类型识别
controller装饰器帮助Controller添加参数实例,这里参数是indexService,前加注解inject,在Controller类的constructor调用时,能取到inject注入的service实例,再将这个实例添加到该Controller的私有变量service中生成实例,在其它方法中直接通过this.indexService调用
inject将类型定义到反射当中,定义时从container中取类型实例放到反射中
container在创建时绑定类型的key和实例到其map当中
import { inject, TYPES } from "./Container";
import { IIndexService } from "./IndexService";
import 'reflect-metadata'
function getParam(str: string) {
/\\((.*)\\)/.test(str);
return RegExp.$1.split(',');
}
//不熟
function hasKey<O extends Object>(key: PropertyKey, o: O): key is keyof O {
return o.hasOwnProperty(key)
}
//不熟
function controller<T extends new (...args: any[]) => {}>(constructor: T) {
class Controller extends constructor {
constructor(...args: any[]) {
super(...args);
let params = getParam(constructor.toString());
for (let identity of params) {
if (hasKey(identity, this)) {
this[identity] = Reflect.getMetadata(TYPES[identity], constructor)
}
}
}
}
return Controller;
}
@controller
class IndexController {
private indexService: IIndexService
constructor(@inject(TYPES['indexService'])indexService?: IIndexService) {
this.indexService = <IIndexService>indexService;
}
log() {
this.indexService.info('hello world');
}
}
let instance = new IndexController();
instance.log()
export interface IIndexService {
info(str: string): void
}
export class IndexService implements IIndexService {
info(str: string): void {
console.log(str)
}
}
import { IndexService } from "./IndexService";
export class createIoc {
private container: Map<Symbol, Object> = new Map<Symbol, Object>()
get(key: Symbol) {
let item = this.container.get(key)
if (item) {
return item
} else {
throw Error('...')
}
}
bind(key: Symbol, cb: Function) {
if (!this.container.has(key)) {
let item = cb();
this.container.set(key, item)
}
}
}
interface ITYPE {
[key: string]: Symbol
}
//不熟
export function inject(serviceIdentifier: Symbol) {
return function (target: Function, targetKey: string, index: number) {
if (!targetKey) {
Reflect.defineMetadata(serviceIdentifier, container.get(serviceIdentifier), target)
}
}
}
export const TYPES: ITYPE = {
'indexService': Symbol.for('indexService')
}
const container = new createIoc();
container.bind(TYPES['indexService'], () => new IndexService)
export { container }