Типобезопасность
Главное правило InferDI: граф зависимостей живёт в системе типов. Неверный граф - перепутанный порядок аргументов, незарегистрированный ключ, singleton, который тянется к scoped-состоянию - это ошибка типа прямо в редакторе, а не stack trace, который вы найдёте под нагрузкой. Всё, что компилятор может доказать статически, проверяется статически; runtime-защита нужна только для того, что проскользнуло через as-касты и динамические ключи.
Сигнатуры конструкторов
registerClass проверяет кортеж зависимостей по параметрам конструктора.
class Logger {}
class Db {}
class UserRepo {
constructor(logger: Logger, db: Db) {}
}
new Container()
.registerClass('logger', Logger, [])
.registerClass('db', Db, [])
.registerClass('users', UserRepo, ['logger', 'db'])Если конструктор изменится, регистрация должна измениться вместе с ним. Кортеж ['db', 'logger'] будет отклонён, потому что первый параметр ожидает Logger.
Уникальность ключей
Каждая регистрация возвращает расширенный тип контейнера. Повторная регистрация того же ключа через fluent API отклоняется:
new Container()
.registerValue('dsn', 'postgres://localhost/app')
.registerValue('dsn', 'sqlite://memory')В тестах для намеренной замены используется .override().
Время жизни в типе
Каждая запись хранит тип значения и вид времени жизни. Система типов фильтрует зависимости так, чтобы singleton не мог напрямую зависеть от scoped- или transient-сервисов.
new Container()
.registerClass('request', RequestContext, [], 'scoped')
.registerClass('users', UserService, ['request'], 'singleton')Runtime-проверки в strict mode остаются вторым рубежом защиты для as-кастов, динамических ключей, захваченных внешних контейнеров и циклов зависимостей.
