TS中模块和命名空间的简单认知

TS中模块和命名空间的简单认知

module

在很多时候,我们称某个文件为一个模块,但是,到底什么样的文件才称之为一个模块,是否有某种”契约关系”。今天看了ts官方文档有点明白了有关模块的这种”契约关系”:

模块是自声明的,两个模块之间的关系是通过在文件级别上使用import和export建立的。说得无耻一点,只要你在文件中使用了import和export语法,就可以将其视为一个模块。
ts官方文档如是说:TypeScript和ECMAScript2015一样,任何包含顶级import或者export的文件都被当成一个模块。其实,也不一定是顶级。以上就是对什么叫模块的简单认知。

export

任何声明:变量、函数、类、接口等都可以通过export关键字导出。这里要特别提醒大家的是,此处的export和CommonJS规范中的exports是万万不同的,不要搞混淆哦。

  //导出接口
  export interface StringValidator {
    isAcceptable(s: string): boolean;
  }

  //导出变量
  export const numberRegexp = /^[0-9]+$/;

  //导出类
  export class ZipCodeValidator implements StringValidator
  {
    isAcceptable(s: string) {
      return s.length === 5 && numberRegexp.test(s)
    }
  }

  //另一种导出方式
  export {StringValidator, numberRegexp, ZipCodeValidator }

  //假如在一个模块里,只导出一个类或函数,那么最佳实践就是用默认导出语法

  export default function Test (s: string) : boolean {
    return s.length === 5 
  }

import

导入就如同导出一样简单


  //the firt way
  import{ StringValidator, numberRegexp, ZipCodeValidator } from "./ZipCodeValidator"

  //another way
  import * as validator from "./ZipCodeValidator"

  let zip = new validator.ZipCodeValidator()

  //如果是默认导出的话,可以直接这么导入
  import test from " 那个默认导出的文件 "

ts中的模块扩展

你可能经常需要去扩展一个模块的功能,在js中我们经常在某个对象上,或者说是原型链上去扩展新功能。而在模块中,最佳实践是导出一个新的实体来提供新的功能。

  //Calculator.ts
  export class Calculator {
    private current = 0;
    private memery = 0;
    private operator: string;

    //charCodeAt() 返回指定位置的字符编码
    processDigit(digit: string, currentValue: number){
      if(digit >= "0" && digit <= "9"){
        return currentValue * 10 + (digit.charCodeAt(0) - "0".charCodeAt(0))
      }
    }
  }

  //现在来扩展它
  import { Calculator } from "./Calculator"

  class ProgrammerCalculator extends Calculator {
    static digits = ["0", "1", "2", "3", "4"];
    constructor(public base: number){
      super()
      if(base <= 0 || base > ProgrammerCalculator.digits.length){
        throw new Error ("base has to be within 0 to 16 inclusive")
      }
    }
    protected processDigit(digit: string, currentValue: number){
      if(ProgrammerCalculator.digits.indexOf(digit) >= 0 ) {
        return currentValue * this.base + ProgrammerCalculator.digits.indexOf(digit)
      }
    }
  }

  //导出
  export { ProgrammerCalculator as Calculator }

  //另:在模块中不要使用命名空间哦!

namespace

在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内。如果想在命名空间外访问,则用export导出。用关键字namespace来声明命名空间,另,现在仍有很多代码用module来声明命名空间,人呐应当与时俱进,建议用namespace替换掉module,看着顺眼了好多。

分离到多文件

当应用变得很大时,我们需要将代码分离到不同的文件中,以便于维护。这就是传说中的多文件中的命名空间。

  //Validation.ts
  namespace Validation {
    export interface StringValidator {
      isAcceptable(s:string): boolean;
    }
  }

  //LettersOnlyValidator.ts
  /// <reference path="./Validation" />
  namespace Validation {
    const lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
      isAcceptable( s: string ) : boolean {
        return lettersRegexp.test(s);
      }
    }
  }

  //ZipCodeValidator.ts
  /// <reference path="./Validation.ts" />
  namespace Validation {
    const numberRegexp = /^[0-9]+$/;
    export class ZipCodeValidatior implements StringValidator {
      isAcceptable( s: string ) : boolean {
        return s.length === 5 && numberRegexp.test(s)
      }
    }
  }

  //Test.ts
  ///<reference path="Validator.ts" />
  ///<reference path="LettersOnlyValidator.ts" />
  ///<reference path="ZipCodeValidator.ts" />
  let strings = ["Hello", "98502", "101"];
  let validators: { [s: string ] : Validation.StringValidator } = {};
  validators["ZIP code"] = new Validation.ZipCodeValidator();
  validators["Letters only"] = new Validation.LettersOnlyValidator();

  for (let s of strings ) {
    for( let name in validators ) {
      console.log(""" + s + "" " + (validators[name]).isAcceptable(s) ? "matches" : " does not match " + name)
    }
  }

  //Summery:
  //在ts中引用带命名空间的文件,用三斜线指令引入要引用的文件。但貌似在实际开发过程中,我们还是用模块用得比较多。
别名

简化命名空间的操作方法:import q = x.y.z 给常用的对象起一个短的名字。但不要和加载模块的 import x = require(“name”)的语法弄混了,这里的语法只是为指定的符号创建一个别名而已。

  namespace Shapes {
    export namespace Polygons {
      export class Triangle {}
      export class Square {}
    }
  }

  import polygons = Shapes.Polygons;
  let sq = new polygons.Square();

  //当用多层命名空间嵌套的时候,使用此语法会大大提升你的开发效率哦

特别重申: 不要对模块使用命名空间,使用命名空间是为了提供逻辑分组和避免命名冲突。模块本身已经是一个逻辑分组,并且它的名字是由导入这个模块的代码指定,所以没有必要为导出的对象增加额外的模块层。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值