依赖关系
声明了标识符和依赖项之后,就需要在依赖项之间声明依赖关系。
有两种依赖项需要声明依赖关系:
- 类依赖项
- 工厂函数依赖项
在类依赖项上声明依赖关系
在类依赖项上声明依赖关系,可以用 Inject
装饰器:
class MapService { constructor( @Inject(SatelliteService) private readonly satellite: SatelliteService ) {}}
也可以使用 createIdentifier
方法创建的标识符:
interface IPlatformService {}const IPlatformService = createIdentifier<IPlatformService>('platform')class DialogService { constructor( @IPlatformService private readonly platformSrc: IPlatformService ) {}}
可选依赖
如果在实例化一个依赖项时,它的依赖未被注入器所持有,那么就会抛出错误。
class MapService { constructor( @Inject(SatelliteService) private readonly satellite: SatelliteService ) {}}const injector = new Injector([[MapService]])injector.get(MapService) // ERROR
有时候,你会想在无法获取到一个依赖时仍然能够继续实例化过程(特别是在代码作为 SDK 给其他开发者使用时),此时你应当将 Inject
替换为 Optional
来标记这个依赖是可选的:
class MapService { constructor( @Optional(SatelliteService) private readonly satellite?: SatelliteService ) {}}const injector = new Injector([MapService])injector.get(MapService)
即使 SatelliteService
未被提供,MapService
仍可以实例化,只是 satellite
属性为 undefined
而已。
多值依赖
类似于可选依赖,可以用 Many
装饰器标识一个标识符注入多个依赖项:
class MapService { constructor( @Many(ISatelliteService) private readonly satellites: ISatelliteService[] ) {}}const injector = new Injector([ [MapService], [ISatelliteService, { useClass: GPSSatellite }], [ISatelliteService, { useClass: BeidouSatellite }],])injector.get(MapService)
在工厂函数依赖项上声明依赖关系
只需要在 deps
中列出即可:
const item = [ I18NNumberTranspiler, { useFactory: (i18nService: I18NService) => { return i18nService.isChinese() ? new ChineseNumberTranspiler() : new EnglishNumberTranspiler() }, deps: [[I18NService]], },]
工厂函数一样可以声明可选依赖和多值依赖,只是语法会稍有不同:
const item = [ [ISatelliteService, { useClass: GPSSatellite }], [ISatelliteService, { useClass: BeidouSatellite }], [IMapService, { useFactory: (satellites: ISatelliteService[]) => new MapService(satellites), deps: [[new Many(), ISatelliteService]] }]]
forwardRef
在下面的例子当中 Person
先于 Father
声明,但是又依赖于 Father
,这种情况下,你需要使用 forwardRef
来封装一次 Father
,否则 redi 在记录依赖关系时, Father
的值会是 undefined
。如果这种情况确实发生了,redi 会报错。
import { Self, SkipSelf } from '@wendellhu/redi'class Person { constructor( @Self() @Inject(forwardRef(() => Father)) private readonly father: Father, @SkipSelf() @Inject(forwardRef(() => Father)) private readonly grandfather: Father ) {}}class Man extends Person {}class Father extends Man { changeDiaper(): void {}}
💡
这和 TypeScript 如何编译 class 有关。在装饰器生效时,
Father
类所对应的标识符的值是 undefined
。