inversify#decorate TypeScript Examples

The following examples show how to use inversify#decorate. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: component.ts    From malagu with MIT License 6 votes vote down vote up
export function applyComponentDecorator(option: ComponentOption, target: any) {

    const isAlreadyDecorated = Reflect.hasOwnMetadata(inversify_METADATA_KEY.PARAM_TYPES, target);

    if (!isAlreadyDecorated) {
        decorate(injectable(), target);
    }

    const metadata: ComponentMetadata = {
        target,
        ids: Array.isArray(option.id) ? option.id : [ option.id || target ],
        sysTags: option.sysTags!,
        rebind: option.rebind!,
        proxy: option.proxy!,
        scope: option.scope!,
        name: option.name,
        tag: option.tag,
        default: option.default,
        when: option.when,
        onActivation: option.onActivation
    };

    let metadatas: ComponentMetadata[] = Reflect.getMetadata(
        METADATA_KEY.component,
        Reflect
    );

    if (!metadatas) {
        metadatas = [];
        Reflect.defineMetadata(
            METADATA_KEY.component,
            metadatas,
            Reflect
        );
    }
    metadatas.push(metadata);
    return metadata;
}
Example #2
Source File: multiInject.ts    From reactant with MIT License 6 votes vote down vote up
export function multiInject(serviceIdentifier: ServiceIdentifier<any>) {
  return (target: object, key?: string, index?: number) => {
    decorate(
      multiInjectWithInversify(serviceIdentifier) as ClassDecorator,
      target,
      index
    );
  };
}
Example #3
Source File: inversify.config.ts    From GWebGPUEngine with MIT License 5 votes vote down vote up
// @see https://github.com/inversify/InversifyJS/blob/master/wiki/inheritance.md#what-can-i-do-when-my-base-class-is-provided-by-a-third-party-module
decorate(injectable(), EventEmitter);
Example #4
Source File: createContainer.ts    From reactant with MIT License 5 votes vote down vote up
export function bindModules(container: Container, modules: ModuleOptions[]) {
  const provideMeta = getMetadata(METADATA_KEY.provide);
  for (const module of modules) {
    if (typeof module === 'function') {
      // auto decorate `@injectable` for module.
      if (!provideMeta.has(module)) decorate(injectable(), module);
      autoDecorateParams(module);
      container.bind(module).toSelf();
    } else if (typeof module === 'object') {
      if (isClassProvider(module)) {
        // auto decorate `@injectable` for module.useClass
        if (!provideMeta.has(module.useClass))
          decorate(injectable(), module.useClass);
        autoDecorateParams(module.useClass);
        container.bind(module.provide).to(module.useClass);
      } else if (Object.hasOwnProperty.call(module, 'useValue')) {
        container
          .bind(module.provide)
          .toConstantValue((module as ValueProvider).useValue);
      } else if (isFactoryProvider(module)) {
        container
          .bind(module.provide)
          .toFactory((context: interfaces.Context) => {
            const deps = module.deps || [];
            const depInstances = deps.map((identifier) => {
              // TODO: refactor with `is` assertion
              const provide =
                (identifier as DependencyProviderOption).provide ||
                (identifier as ServiceIdentifier<any>);
              if (
                (identifier as DependencyProviderOption).optional &&
                !context.container.isBound(
                  (identifier as DependencyProviderOption).provide
                )
              ) {
                return undefined;
              }
              return context.container.get(provide);
            });
            return module.useFactory(...depInstances);
          });
      } else if (typeof module.provide === 'function') {
        // auto decorate `@injectable` for module.provide
        if (!provideMeta.has(module.provide))
          decorate(injectable(), module.provide);
        autoDecorateParams(module.provide);
        container.bind(module.provide).toSelf();
      } else {
        throw new Error(`${module} option error`);
      }
    } else {
      throw new Error(`${module} option error`);
    }
  }
  // load modules with `@injectable` decoration, but without `@optional` decoration.
  container.load(autoBindModules());
}
Example #5
Source File: inject.ts    From reactant with MIT License 5 votes vote down vote up
/**
 * ## Description
 *
 * You can use `@inject()` to perform the required dependency injection module to decorate in the constructor of an injectable class.
 *
 * If the default is a dependency injection of the class itself as a type, e.g. `@inject(Foo) foo: Foo`, then it is exactly the same as `foo: Foo`.
 *
 * ## Example
 *
 * ```ts
 * @injectable()
 * class Bar {
 *   getValue() {
 *     return 'bar';
 *   }
 * }
 *
 * @injectable()
 * class Foo {
 *   getValue() {
 *     return 'foo';
 *   }
 * }
 *
 * @injectable()
 * class FooBar {
 *   constructor(@inject() public bar: Bar, @inject('foo') public foo: Foo) {}
 * }
 *
 * const fooBar = testBed({
 *   modules: [
 *    Bar,
 *    { provide: 'foo', useClass: Foo },
 *   ],
 *   main: FooBar,
 * });
 *
 * expect(fooBar.instance.foo.getValue()).toBe('foo');
 * ```
 */
export function inject(serviceIdentifierOrFunc?: ServiceIdentifierOrFunc<any>) {
  return (target: object, key?: string, index?: number) => {
    const self = Reflect.getMetadata(METADATA_KEY.paramtypes, target)[index!];
    let serviceIdentifier: ServiceIdentifierOrFunc<any>;
    if (serviceIdentifierOrFunc instanceof LazyServiceIdentifer) {
      serviceIdentifier = serviceIdentifierOrFunc;
    } else if (typeof serviceIdentifierOrFunc === 'undefined') {
      serviceIdentifier = forwardRef(() =>
        lookupServiceIdentifier(target, self, index)
      );
    } else {
      serviceIdentifier = forwardRef(() =>
        lookupServiceIdentifier(target, serviceIdentifierOrFunc, index)
      );
    }
    decorate(
      injectWithInversify(serviceIdentifier) as ClassDecorator,
      target,
      index
    );
  };
}
Example #6
Source File: multiOptional.ts    From reactant with MIT License 5 votes vote down vote up
export function multiOptional(serviceIdentifier: ServiceIdentifier<any>) {
  return (target: object, key?: string, index?: number) => {
    const paramtypes = Reflect.getMetadata(METADATA_KEY.paramtypes, target);
    setMetadata(METADATA_KEY.optional, paramtypes[index!], serviceIdentifier);
    decorate(multiInject(serviceIdentifier) as ClassDecorator, target, index);
    decorate(optionalWithInversify() as ClassDecorator, target, index);
  };
}
Example #7
Source File: optional.ts    From reactant with MIT License 5 votes vote down vote up
/**
 * ## Description
 *
 * You can use `@optional()` to decorate an optionally injected module.
 *
 * If other modules have no relevant dependency injection or are also optionally injected, the module will not be injected by default unless the injected module is imported in the `modules` parameter.
 *
 * ## Example
 *
 * ```ts
 * @injectable()
 * class Bar {
 *   getValue() {
 *     return 'bar';
 *   }
 * }
 *
 * @injectable()
 * class Foo {
 *   getValue() {
 *     return 'foo';
 *   }
 * }
 *
 * @injectable()
 * class FooBar {
 *   constructor(@optional() public bar: Bar, @optional('foo') public foo: Foo) {}
 * }
 *
 * const fooBar = testBed({
 *   modules: [
 *    { provide: 'foo', useClass: Foo },
 *   ],
 *   main: FooBar,
 * });
 *
 * expect(fooBar.instance.foo.getValue()).toBe('foo');
 * expect(fooBar.fooBar.bar).toBeUndefined();
 * ```
 */
export function optional(serviceIdentifier?: ServiceIdentifier<any>) {
  return (target: object, key?: string, index?: number) => {
    const paramtypes = Reflect.getMetadata(METADATA_KEY.paramtypes, target);
    setMetadata(METADATA_KEY.optional, paramtypes[index!], serviceIdentifier);
    decorate(inject(serviceIdentifier) as ClassDecorator, target, index);
    decorate(optionalWithInversify() as ClassDecorator, target, index);
  };
}
Example #8
Source File: injectable.ts    From reactant with MIT License 4 votes vote down vote up
/**
 * ## Description
 *
 * You can use `@injectable()` to decorate an injectable module, which will also allow `emitDecoratorMetadata` to take effect in the decorated class, so the corresponding `@inject()` is optional.
 *
 * But if you don't want to use `@injectable()`, then the dependency injection decorator for constructors such as `@inject()` is required, and it must be imported in the corresponding `modules` startup configuration. Therefore, in most cases, it is recommended to use `@injectable()`.
 *
 * ## Example
 *
 * ```ts
 * @injectable()
 * class Bar {
 *   getValue() {
 *     return 'bar';
 *   }
 * }
 *
 * class Foo {
 *   constructor(@inject() public bar: Bar) {}
 * }
 *
 * @injectable()
 * class FooBar {
 *   constructor(public bar: Bar, public foo: Foo) {}
 * }
 *
 * const fooBar = testBed({
 *   modules: [
 *    Foo // `Foo` is required, but `Bar` will be injected automatically.
 *  ],
 *   main: FooBar,
 * });
 *
 * expect(fooBar.instance.foo.getValue()).toBe('foo');
 * ```
 *
 * If you use JavaScript, then you can only use `@injectable()` to define the full dependency metadata.
 *
 * ```js
 * @injectable()
 * class Bar {
 *   getValue() {
 *     return 'bar';
 *   }
 * }
 *
 * @injectable()
 * class Foo {
 *   getValue() {
 *     return 'foo';
 *   }
 * }
 *
 * @injectable({
 *   deps: [Bar,  { provide: 'foo' }],
 * })
 * class FooBar {
 *   constructor(bar, foo) {
 *     this.bar = bar;
 *     this.foo = foo;
 *   }
 * }
 *
 * const fooBar = testBed({
 *   modules: [
 *    Bar,
 *    { provide: 'foo', useClass: Foo },
 *  ],
 *   main: FooBar,
 * });
 *
 * expect(fooBar.instance.foo.getValue()).toBe('foo');
 * ```
 */
export function injectable(options: ModuleDecoratorOptions = {}) {
  return (target: any) => {
    const { deps = [] } = options;
    deps.forEach((option, index) => {
      if (typeof option === 'function') {
        decorate(inject(option) as ClassDecorator, target, index);
      } else if (toString.call(option) === '[object Object]') {
        if (option.optional && !option.multi) {
          decorate(optional(option.provide) as ClassDecorator, target, index);
        } else if (option.multi && !option.optional) {
          decorate(
            multiInject(option.provide) as ClassDecorator,
            target,
            index
          );
        } else if (option.multi && option.optional) {
          decorate(
            multiOptional(option.provide) as ClassDecorator,
            target,
            index
          );
        } else if (option.provide) {
          decorate(inject(option.provide) as ClassDecorator, target, index);
        } else {
          throw new Error(`@injectable ${option} option error`);
        }
      } else {
        throw new Error(`@injectable ${option} option error`);
      }
    });
    // it has to use `Reflect.getMetadata` with metadata, it just get all injectable deps.
    // so add the services set for `injectable` services.
    setMetadata(METADATA_KEY.provide, target, target);
    decorate(injectify(), target);
    return target;
  };
}