zoukankan      html  css  js  c++  java
  • TypeScript模块系统、命名空间、声明合并

    命名空间

    命名空间能有效避免全局污染。在ES6引入模块之后,命名空间就较少被提及了。如果使用了全局的类库,命名空间仍是一个好的解决方案。

    namespace Shape{
       const pi = Math.PI;
       // 使用export关键字导出,可以在全局空间内可见
       export function circle(r: number) {
          return pi * r ** 2
       }
       square(5)
    }
    Shape.circle(10); // 可以在全局空间访问导出的
    import circle = Shape.circle; // 为命名空间内的变量起个别名,要清楚此处import与模块化的import含义不一样
    circle(20);

    随着程序的扩张,命名空间也会很大,需要对其进行拆分,在不同的文件中使用同名命名空间,他们之间共享命名空间。

    // space1.ts
    /// <reference path="space2.ts" />  // 三斜线引用标签告诉编译器,两个文件中的命名空间内部存在着依赖关系
    namespace Shape{
       export function square(x: number) {
          return x*x;
       }
       circle(10); // 只有circle被export后,这里才能访问
    }
    
    // space2.ts
    /// <reference path="space1.ts" />
    namespace Shape{
       const pi = Math.PI;
       // 使用export关键字导出,可以在全局空间内可见
       export function circle(r: number) {
          return pi * r ** 2
       }
       square(5); 
    }

    命名空间最好不要和模块一起混用

    模块化系统

    TypeScript对ES6和CommonJS两种模块系统都有很好的支持,我们基本可以沿用以前的写法。但两者不要混用,如果出现混用,就要使用TS准备的兼容性写法。

    先来看看ES6和CommonJS各自的写法

    // ES6导入
    import { a, b } from './Modular System/es6/a';
    import { a as f } from './Modular System/es6/a';
    import * as All from './Modular System/es6/a';
    import abc from './Modular System/es6/b';
    import Obj from './Modular System/es6/a'
    // ES6导出
    export defalut Obj;
    export {a,b,c};
    export {d as D};
    export {D as C}  from './a'; // 将a.ts中的D重新命名并导出,这种用法只能对a.ts中的非默认导出有效
    
    // CommonJS导入
    let c1 = require('./Modular System/node/a.ts');
    let c2 = require('./Modular System/node/b');
    // CommonJS导出
    module.exports = a;  // 将a变量导出
    exports.c = 3;
    exports.d = 4;
    相当于
    module.exports = {c:3, d:4}
    如果两种方式并存,module.exports将会覆盖exports.c这种方式的导出

    两种模块在导入导出时互不兼容:

    • 导出:ES6允许同时存在export default和export多个变量,而CommonJS只允许有一种形式的导出,其中一种会把另外一种覆盖掉。
    • 导入:ES6可以按需导入也可以全部导入,而CommonJS只能全部导入。

    如果在ES6模块中抛出数据,在非ES6模块中导入,就会出现问题。因此尽量不要混用不同的模块化系统。如果迫不得已,可以使用TS提供的兼容性语法:

    // 导出
    export = a; 
    // 导入
    import c4 = require('../es6/c');
    /* 
    1.如果使用以上方法导出,此文件不允许有其它形式的导出 
    2.以上形式的导出的数据,不仅可以用以上语法导入,还可以用es6的方式导入。前提是tsconfig.json中的"esModuleInterop":true配置项要开启。
    */

    声明合并

     编译器会把程序的多个地方具有相同名称的声明合并成一个,这样可以将程序散落在各处的重名声明合并在一起。

    例如:

    interface StateMerge {
       x: number,
       y: string,
    }
    interface StateMerge {
       y: string;
       foo(bar: string[]): string[], 
    }
    // 此时会将两个声明的同名接口成员合并
    let stateMerge: StateMerge = {
       x: 1,
       y: "15",
       foo(bar: any) {
          return bar
       }
    };

    如果合并的两个结构内成员重名怎么办?

    • 对于非函数成员,必须类型一致,否则报错。
    • 对于函数成员,会发生重载,重载的顺序按照以下规则。
    interface StateMerge {
       x: number,
       y: string,
       foo(bar: number): number; // 4
       foo(bar: string): string; // 5
       foo(bar: "b"): number;    // 2
    }
    interface StateMerge {
       y: string;
       foo(bar: string[]): string[], // 3
       foo(bar: "a"): number,  // 1
    }

    接口内部按照先后顺序。接口之间,声明在后的接口函数成员排序更靠前。

    如果出现自变量,排名最靠前。后面的接口中的排在第一位,前面的接口排在第二位。上述排序如注释所示。

    函数和命名空间的合并

    function Lib() {
    }
    namespace Lib{
       export let version = '1.0'
    }
    console.log(Lib.version); // 相当于为函数Lib添加了属性

    类和命名空间的合并

    class C{
    }
    namespace C{
       export let state = 1
    }
    console.log(C.state); // 相当于为类C添加了state属性

    此外,还可以为枚举增加属性。

    注意:在命名空间与类、函数进行生命合并的时候,一定要将命名空间放在类、函数之后。否则报错。

  • 相关阅读:
    JVM,反射与动态代理
    11款实用的一句话网站设计代码
    Winform TextBox中只能输入数字的几种常用方法(C#)
    列表checkbox全选
    函数调用约定
    vs编译后在本机能运行,在别的机器上运行提示runtime Error的问题
    学习地形编程(一)
    Ogre中动态三维鼠标的实现
    讲讲volatile的作用
    绕任意轴旋转的推导
  • 原文地址:https://www.cnblogs.com/V587Chinese/p/11519477.html
Copyright © 2011-2022 走看看