TypeScript 来做依赖注入的限制

时间: 2019-08-13阅读: 533标签: 代码

依赖注入 是编写可测试/复用代码的关键。 在 TypeScript 中所有对象、属性和方法都有类型,可以大幅简化人工标注的代码,这让很多人重新考虑在 JavaScript 中实现依赖注入。 比如 Angular2 以后的 DI 实现 。 本文用来讨论 TypeScript 仍然无法解决哪些问题,以及相关技术可能存在的风险。

首先简单过一下基于 TypeScript 做依赖注入的步骤。 ES6 中提出了 Reflect 用来访问和操作对象对象属性。 而 Reflect Metadata 提案 让 Reflect API 可以提供对类型的元数据进行操作的方法。 这样就可以在 tsc 编译时产出注册元数据代码,在运行时就可以读到编译时的类型了,这一类型就提供了依赖注入的 Token。 运行时的注入器根据函数签名的类型拿到依赖关系,再根据类型对应的 Provider 来创建依赖树。


装饰器可能和标准分裂

TypeScript 编译 Reflect Metadata 需要打开一个叫做 emitDecoratorMetadata 的开关, 但这个开关只有在存在装饰器的方法上起作用。 不知这是设计缺陷还是故意的,总之要通过加装饰器来生成 metadata,两个特性是绑在一起的。 也就是说基于 TypeScript 做依赖注入一定要用 decorator。 坏消息是 ECMA 最新的 Proposal Decorators 和 TypeScript 提出的装饰器很不一样。 如果大量使用相关特性,后续可能面临代码迁移。


函数无法装饰

目前 TypeScript 的编译器中,装饰器不能修饰函数(对象之外的独立 function)。 装饰器无法装饰独立的方法,也就是说无法为独立的工厂方法自动生成依赖列表。 只能把工厂方法改成工厂类,否则就需要手动声明依赖。

A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. –typescriptlang.org

这就是为什么 Angular 中只有 factory 需要手动声明依赖列表 :

export let heroServiceProvider =
  { provide: HeroService,
    useFactory: heroServiceFactory,
    deps: [Logger, UserService]
  };

NestJS 也只有 factory 类型的 provider 需要提供 inject 数组:

const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider: OptionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};


interface 仍然需要显式声明

这一小节标题比较抽象,需要先看个例子。 这是一个依赖注入的典型场景(省略了一些注册、装饰器等操作):

// 声明一个 Person 类
class Person {
  constructor(p: Parent, a: Age) {}
}

// 请求创建一个 Person 对象
const person = injector.create(Person)

依赖注入的核心设计就是使用和创建分离。 这里我们要用一个 Person 对象,如何创建完全交给 injector,它会去分析并创建 Person 的依赖( [Parent, Age] ),然后再创建 Person 并返回。 如果 Parent 和 Age 不是具体的类而是接口,那么运行时拿到的依赖列表将会是 [Object, Object] ,这样 injector 就无法知晓和创建依赖了。 所以对于接口类型,仍然需要声明一下给运行时一些信息,比如这样:

class Person {
  constructor(@inject('IParnet') p: IParent, @inject('IAge') a: Age) {}
}

其实类似这样的声明有个通用的名字叫做 Inject Token,本是用于基本数据类型注入,或希望通过类型之外的信息来创建的时候。 只是在 TypeScript 中,即使是非常常用的接口也必须采用这种相对复杂的写法。

原文:https://harttle.land/2019/08/12/typescript-limit-for-dependency-injection.html


站长推荐

1.阿里云: 本站目前使用的是阿里云主机,安全/可靠/稳定。点击领取2000元代金券、了解最新阿里云产品的各种优惠活动点击进入

2.腾讯云: 提供云服务器、云数据库、云存储、视频与CDN、域名等服务。腾讯云各类产品的最新活动,优惠券领取点击进入

3.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/4666

写业务代码最容易掉的8种坑

线程、线程同步、池、网络连接、网络链路、对象实例化、内存等方面的基础是最容易犯错的地方,搞清楚框架内部对于这些基础资源的的使用方式,根据最佳实践进行合理配置,这是业务开发时需要特别关注的点。

原生 js 中应该禁止出现的写法,以提高代码效率和安全性

严格模式下,在 ES6 之前应禁止使用。ES6 开始可以使用,函数的作用域为声明该函数的块内部。非严格模式下应禁止使用。禁止使用 eval。eval 比一般 javascript 执行要慢,因为浏览器对 javascript 进行了优化。

你写的代码就是你的犯罪证据

最近我工作的主要内容,是在和别人结对编程,以对一个大型的遗留系统项目进行重构。过程中,我发现一个特别有意思的东西,我重构了很多的 if 语句。

如何用不到200行代码写一款属于自己的JS类库

JavaScript 的核心是支持面向对象的,同时它也提供了强大灵活的 OOP 语言能力。本文将使用面向对象的方式,来教大家用原生js写出一个类似jQuery这样的类库。我们将会学到如下知识点

当一个程序员写不出代码了,该怎么办?

即使是最优秀的程序员也会遭遇无法解决的软件工程问题。碰到这样的问题,并不一定意味着你缺乏技能或知识。编程不是一项容易的工作,我们可以通过采取非正统的方法来保持你想要的生产力水平

Js代码压缩工具推荐

JavaScript 代码压缩是指去除源代码里的所有不必要的字符,而不改变其功能的过程。这些不必要的字符通常包括空格字符,换行字符,注释以及块分隔符等用来增加可读性的代码,但并不需要它来执行。

如何处理前任程序员留下的代码

作为软件工程师不可避免会遇到的一个场景是:我们在改变或添加一个功能到不是我们创建的、我们不熟悉的、与我们负责的系统部分无关的代码中时,会遇到麻烦。虽然这可能会是一个繁琐而艰巨的任务

接手代码太烂,要不要辞职?

朋友发表了一条说说:入职新公司,从重构代码到放弃”,我就问他怎么了?他说,刚进一家新公司,接手代码太烂,领导让我先熟悉业务逻辑,然后去修复之前项目中遗留的bug,实在不行就重构

JS无形装逼,最为致命

单行简洁的代码很难维护(有时甚至难以理解),但这并不能阻止广大攻城狮们脑洞,在编写简洁的代码后获得一定的满足感。以下我最近的一些收藏javascript精简代码集合。

前端代码美化的艺术

原本只是想简单的聊一下代码格式化的问题,无奈本文拖沓了很久,在此期间,我又思考了很多,我越来越觉得代码格式化是一门艺术。为了衬托“艺术”二字,可能叫“代码美化”更贴切一点,但是本文的深度远没有标题那么宏大

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!

文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全运营推广