TypeScript手册翻译系列7-常见错误与Mixins

常见错误

下面列出了在使用TypeScript语言和编译器期间,经常会遇到的一些常见错误。

"tsc.exe" exited with error code 1.

解决方案: 检查文件编码为UTF-8 - https://typescript.codeplex.com/workitem/1587

external module XYZ cannot be resolved

解决方案:检查模块路径是大小写敏感https://typescript.codeplex.com/workitem/2134

Mixins

除了传统的面向对象OO层级关系以外,利用可重用组件来构建类的另外一种流行方式是将更简单的局部类(simpler partial classes)组合来构建。你可能熟悉类似Scala语言中mixins或traits思想,这种模式已经在JavaScript中开始流行。

Mixin举例

下面代码展示了TypeScript中如何建模mixins,然后我们来分析这段代码是如何工作的。

// Disposable Mixin
class Disposable {
    isDisposed: boolean;
    dispose() {        
        this.isDisposed = true;
    }
 


// Activatable Mixin
class Activatable {
    isActive: boolean;
    activate() {        
        this.isActive = true;
    }
    deactivate() {        
        this.isActive = false;
    }
}

class SmartObject implements Disposable, Activatable {
    constructor() {
        setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);
    }
 
    interact() {        
        this.activate();
    }
    
    // Disposable
    isDisposed: boolean = false;
    dispose: () => void;    
    // Activatable
    isActive: boolean = false;
    activate: () => void;
    deactivate: () => void;
}
applyMixins(SmartObject, [Disposable, Activatable]) 

var smartObj = new SmartObject();
setTimeout(() => smartObj.interact(), 1000); 

////////////////////////////////////////
// In your runtime library somewhere
////////////////////////////////////////

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            derivedCtor.prototype[name] = baseCtor.prototype[name];
        })
    }); 
}

理解这个例子

代码例子一开始是两个类,角色就是mixins。可以看出每个类聚焦于一个特定的活动或能力。后面我们将它们混合在一起(mix these together)形成一个有两种能力的新类。

// Disposable Mixin
class Disposable {
    isDisposed: boolean;
    dispose() {        
        this.isDisposed = true;
    }
 
}

// Activatable Mixin
class Activatable {
    isActive: boolean;
    activate() {        
        this.isActive = true;
    }
    deactivate() {        
        this.isActive = false;
    }
}


接下来,我们将这两个mixins组合为一个新类,下面看看如何做到

class SmartObject implements Disposable, Activatable {


上面代码中第一会注意到没有用'extends', 而是用的'implements'关键字。这将类当做接口,只是用了Disposable与Activatable后面的类型而没有用实现。这意味着我们必须提供类中的实现。Except, that's exactly what we want to avoid by using mixins. 

为了满足这个需求,就需要在新类中创建在mixins中的替代者属性(stand-in properties)与成员类型。这样可以让编译器知道在运行时这些成员是存在的。这样我们可以得到mixins的好处,尽管需要付出一些记录代价(bookkeeping overhead)。

// Disposable
isDisposed: boolean = false;
dispose: () => void;
// Activatable
isActive: boolean = false;
activate: () => void;
deactivate: () => void;


接下来,将mixins混合到类中,创建完整的实现。

applyMixins(SmartObject, [Disposable, Activatable])


最后, 创建一个helper函数来做混合。这将遍历mixins的每个属性,并复制到mixins的target类中,用实现来填充这些替代者属性(filling out the stand-in properties with their implementations)。

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            derivedCtor.prototype[name] = baseCtor.prototype[name];
        })
    }); 
}

参考资料

[1] http://www.typescriptlang.org/Handbook#common-errors

[2] TypeScript系列1-简介及版本新特性, http://my.oschina.net/1pei/blog/493012

[3] TypeScript手册翻译系列1-基础类型, http://my.oschina.net/1pei/blog/493181

[4] TypeScript手册翻译系列2-接口, http://my.oschina.net/1pei/blog/493388

[5] TypeScript手册翻译系列3-类, http://my.oschina.net/1pei/blog/493539

[6] TypeScript手册翻译系列4-模块, http://my.oschina.net/1pei/blog/495948

[7] TypeScript手册翻译系列5-函数, http://my.oschina.net/1pei/blog/501273

[8] TypeScript手册翻译系列6-泛型, http://my.oschina.net/1pei/blog/513483

你可能感兴趣的:(TypeScript)