TypeScript发现与理解


1. 模块

模块的特性

  1. ES6的模块自动采用严格模式;
  2. 在ES6模块中,顶层的this的值是undefined,不应该在顶层代码使用this;
  3. export语句输出的接口与其对应的值是动态绑定关系,即通过该接口,可以获取到模块内部实时的值;这一点与CommonJS规范完全不同,CommonJS模块输出的是值的缓存,不存在动态更新;
  4. export 和 import 命令可以并且只能出现在模块顶层的任意位置;如果export 和 import 命令处于块级作用域内,就会报错;这是因为如果export 和 import 命令处于代码块之中,就没法做静态优化了,违背了ES6模块的设计初衷;
  5. 因为:export default命令的本质是:将该命令后面的值,赋给default变量,然后输出一个叫做default的量;
    所以:
    1. 可以直接将一个值写在export default之后;
    2. export default之后不能跟变量声明语句;
  6. import后面的from指定模块文件的位置,可以是相对路径或者绝对路径,.js后缀也可以省略;如果from后面指定的不是路径,只是一个模块名字,那么必须有配置文件能使JavaScript引擎找到该模块的位置;
  7. import命令具有提升效果,会提升到整个模块的顶部,首先执行。这种行为的本质是:import命令是编译阶段执行的,所以它会在所有代码运行之前执行;
  8. 由于import语句是在编译阶段执行,所以import语句中不能包含表达式、变量等只能在运行时才能得到结果的语法结构;
  9. 如果有相同的多条import语句,那么只会执行一次同一条import语句;
  10. 由于 ES6 输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错;
  11. 在 Node 环境中,使用import命令加载 CommonJS 模块,Node 会自动将module.exports属性,当作模块的默认输出,即等同于export default;
  12. 采用require命令加载 ES6 模块时,ES6 模块的所有输出接口,会成为输入对象的属性。
  13. ES6模块与CommonJS模块的区别:
  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  • ES6 模块之中,顶层的this指向undefined;CommonJS 模块的顶层this指向当前模块。

模块导入和导出的各种写法

导出

有以下几种导出方法:

  1. 导出声明:
    直接在(变量、函数、类型、类型别名、接口)声明前添加export关键字;
    示例如下:
    export const numberRegexp = /^[0-9]+$/;
    
    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
                return s.length === 5 && numberRegexp.test(s);
        }
    }
    
  2. 导出语句:
    导出语句可以把需要导出的实例一块导出,也可以对导出的部分重新命名;
    示例如下:
    export const numberRegexp = /^[0-9]+$/;
    
    class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
                return s.length === 5 && numberRegexp.test(s);
            }
    }
    
    export { ZipCodeValidator,numberRegexp };
    export { ZipCodeValidator as mainValidator };
    
  3. 重新导出:
    我们经常会去扩展其它模块,并且只导出那个模块的部分内容。 重新导出功能并不会在当前模块导入那个模块或定义一个新的局部变量;
    示例如下:
    // 导出原先的类但做了重命名
    export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
    
  4. 默认导出:
    每个模块都可以有一个default导出。 默认导出使用default关键字标记;并且一个模块只能够有一个default导出。 需要使用一种特殊的导入形式来导入default导出。标记为默认导出的实体可以省略名字;
    示例如下:
    export default function (s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
    

导入

模块的导入操作与导出一样简单。 可以使用以下import形式之一来导入其它模块中的导出内容:

  1. 导入一个模块中的某个导出内容,也可对于进行重命名::
    格式如下:
    import { 要导出的内容的名字 } from "模块路径";
    import { 要导出的内容的名字 as 新名字 } from "模块路径";
    
    示例如下:
    import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
    let myValidator = new ZCV();
    
  2. 将整个模块导入到一个变量,并通过它来访问模块的导出部分:
    格式如下:
    import * as 新名字 from "模块路径";
    
    示例如下:
    import * as validator from "./ZipCodeValidator";
    let myValidator = new validator.ZipCodeValidator();
    
  3. 导出默认的导出项:
    每个模块都可以有一个default导出。 默认导出使用default关键字标记;并且一个模块只能够有一个default导出。
    导出默认的导邮项目的格式如下:
    import 自定义名字 from "模块路径";
    
    示例如下:
    import JQ from "JQuery";
    
    JQ("button.continue").html( "Next Step..." );
    
  4. 具有副作用的导入模块:
    格式如下:
    import "模块路径";
    
    此种导入,相当于把相应模块的代码插入到了本模块;

export = 和 import = require()

CommonJS和AMD都有一个exports对象的概念,它包含了一个模块的所有导出内容。
它们也支持把exports替换为一个自定义对象。 默认导出就好比这样一个功能;然而,它们却并不相互兼容。 TypeScript模块支持export =语法以支持传统的CommonJS和AMD的工作流模型。
export =语法定义一个模块的导出对象。 它可以是类,接口,命名空间,函数或枚举。
若要导入一个使用了export =的模块时,必须使用TypeScript提供的特定语法import module = require("module")。
示例如下:
ZipCodeValidator.ts

let numberRegexp = /^[0-9]+$/;
class ZipCodeValidator {
    isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
    }
}
export = ZipCodeValidator;

Test.ts

import zip = require("./ZipCodeValidator");

// Some samples to try
let strings = ["Hello", "98052", "101"];

// Validators to use
let validator = new zip();

// Show whether each string passed each validator
strings.forEach(s => {
  console.log(`"${ s }" - ${ validator.isAcceptable(s) ? "matches" : "does not match" }`);
  });

2. 别名

格式:

import 新名字 = x.y.z;

这是一种简化命名空间操作的方法是使用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(); // Same as "new Shapes.Polygons.Square()"

注意:
我们并没有使用require关键字,而是直接使用导入符号的限定名赋值。 这与使用var相似,但它还适用于类型和导入的具有命名空间含义的符号。 重要的是,对于值来讲,import会生成与原始符号不同的引用,所以改变别名的var值并不会影响原始变量的值。


3. 函数语法

  1. 函数类型的表示:
    (参数列表)=>返回值类型
    
  2. 函数的定义:
    function 函数名字(参数列表):返回类型 {
        代码
    }
    
  3. 箭头函数的定义:
    (参数列表):返回类型=>{
        代码
    }
    

4. TypeScript语法特性:

  1. TypeScript的类型注释是可选的,可有可无;并且TypeScript编译器具有类型推断功能;
  2. 函数的参数列表中的可选参数必须放在必须参数的后面;
  3. 函数的参数列表中的默认参数值参数不必非得放在必须参数的后面,它可以放在参数列表的任何位置;当默认值参数不是放在必须参数的后面时,用户必须通过给默认值参数传入undefined来使用默认值参数的默认值;当默认参值参数放在必须参数后面时,默认值参数是可选的,在调用函数时,可以省略默认值参数;
  4. 剩余参数必须是数组类型,并且必须放在能数列表中的最后一个;
  5. 在TypeScript里,类的成员默认为public;
  6. 只读属性必须在声明时或构造函数里被初始化;
  7. 使用存取器时,编译器必须设置为输出ECMAScript 5或更高;不支持降级到ECMAScript 3;
  8. 只带有get不带有set的存取器自动被推断为readonly;这在从代码生成.d.ts文件时是有帮助的,因为利用这个属性的用户会看到不允许够改变它的值;

5. 接口

  1. 当把对象字面量赋值给变量或作为参数传递的时候,该对象字面量不能存在任何“目标类型”(变量类型或者参数类型)不包含的属性时;
  2. 对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配;

你可能感兴趣的:(TypeScript发现与理解)