Skip to content

依赖关系

声明了标识符和依赖项之后,就需要在依赖项之间声明依赖关系。

有两种依赖项需要声明依赖关系:

  • 类依赖项
  • 工厂函数依赖项

在类依赖项上声明依赖关系

在类依赖项上声明依赖关系,可以用 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