跨 CommonJS 模块的 Typescript 继承 - 循环依赖
Posted
技术标签:
【中文标题】跨 CommonJS 模块的 Typescript 继承 - 循环依赖【英文标题】:Typescript Inheritance across CommonJS modules - Circular Dependencies 【发布时间】:2014-08-28 07:11:54 【问题描述】:我无法在使用 typescript 1.0 生成的 CommonJS 模块之间进行继承(tsc
is run using --module commonjs
)
当两个类继承同一个基类,“通过”基类相互调用时,这会失败。
似乎是第一个类导入了基类,它导入了第二个类,第二个类也导入了基类,但最后一个基类导入失败。
下面提供了一个说明此行为的示例。
Typescript 或 CommonJS 规范中是否有任何内容阻止我这样做,或者这是一个错误?
=== 示例 ===
这个迷人的软件因运行Lower.test.ts
而失败。它试图实现的只是将一个单词加载到Lower
中,使其保持小写,然后使用从Base
类继承的toUpper()
方法,使用Upper
类将其转换为大写(这也是继承Base
)
Lower.test.ts
import Lower = require('./Lower')
console.log(new Lower('smallcaps').toUpper())
Base.ts
import Upper = require('./Upper')
class Base
word: string
toUpper(): string
return new Upper(this.word).word
export = Base
Upper.ts
import Base = require('./Base')
class Upper extends Base
constructor(word:string)
super()
this.word = word.toUpperCase()
export = Upper
Lower.ts
import Base = require('./Base')
class Lower extends Base
constructor(word:string)
super()
this.word = word.toLowerCase()
export = Lower
【问题讨论】:
【参考方案1】:通常最好只依赖一个方向 - 根据 SOLID 原则。
但是,由于您始终需要 Base
和 Upper
(即不能没有另一个),您可以将它们添加到同一个模块中...
base.ts
export class Base
word: string
toUpper(): string
return new Upper(this.word).word
export class Upper extends Base
constructor(word: string)
super()
this.word = word.toUpperCase()
lower.ts
import b = require('base')
class Lower extends b.Base
constructor(word: string)
super()
this.word = word.toLowerCase()
export = Lower
app.ts
import Lower = require('lower');
console.log(new Lower('smallcaps').toUpper());
【讨论】:
感谢您的解决方法;我可以接受这样一个事实,即它降低了模块化,但它仍然留下了悬而未决的问题。至于朝一个方向发展,这并不总是有意义的:想象一下这个非常简单的几何应用程序,它实现了Vector
。与许多其他几何图形一样,Vector
可以通过将其乘以另一个 Vector
来进行缩放。创建一个Scalable
类是有意义的,该类Vector
继承,并实现了一个scale()
方法,该方法有一个Vector
作为参数。到这里:继承一个在方法中使用其子类之一的类。
我还是会避免它。如果 Vector 总是可以缩放,为什么 Scalable 是子类。如果不能总是缩放,就不应该有缩放方法,缩放方法应该由Scalable子类添加。【参考方案2】:
经过一些研究和测试,这最终是一个循环依赖的情况。
这个问题已经得到很好的记录,并且已经提出了各种解决方案:
-
在
requiring
:here之前导出
延迟require
或使用注入:here
移动语句:很长的列表here
不幸的是,在 Typescript 中可以设置 import
和 export
语句的位置几乎没有控制,这减少了仅注入的解决方案。下面提供了重写的Base
类。
循环依赖是 javascript 模块化项目中的一个难题。打字稿不知何故使事情变得更糟。对于本应处理大型项目的语言来说,这是个坏消息
编辑 我已经打开了一个案例并向 TypeScript 项目提交了一个建议的转译器修复:here
Base.ts
//This import will "fail" by importing an empty object but is needed to trick the compiler
//An alternative is to design and Upper.d.ts definition file and reference it
import Upper = require('./Upper')
class Base
//Upper is a sub-class of Base and needs to be injected to be instantiated
private _Upper: typeof Upper
word: string
constructor(_Upper: typeof Upper)
this._Upper = _Upper
toUpper(): string
//This where the injection is used
return new this._Upper(this.word).word
getUpperWord(upper: Upper): string
//The injection is not reauired in this case
return upper.word
export = Base
Upper.ts
import Base = require('./Base')
class Upper extends Base
constructor(word:string)
super(Upper)
this.word = word.toUpperCase();
export = Upper
【讨论】:
以上是关于跨 CommonJS 模块的 Typescript 继承 - 循环依赖的主要内容,如果未能解决你的问题,请参考以下文章
编译TypeScript(TypeScript转JavaScript)