参考资料:

一些有用的网址:

资源:

安装:npm install -g typescript
编译:tsc hello.ts
优势是增强了编译器和IDE的功能,包括代码补全、接口提示、跳转到定义、重构等;
TS文件编译后生成JS文件,与检查相关的代码并未生成,这是因为TS只在编译时对代码进行检查,若有错误则直接报错,而在运行时与JS一样不对类型进行检查。编译即使报错,也会生成JS文件。

基础

原始数据类型

介绍5种基本数据类型在TS上的应用。

  1. let isDone:boolean = false; // 布尔
  2. let six:number = 6; // 数值
  3. let notANumber: number = NaN;
  4. let infinityNumber: number = Infinity;
  5. let binaryLiteral: number = 0b1010; // ES6 中的二进制表示法
  6. let octalLiteral: number = 0o744; // ES6 中的八进制表示法
  7. // 非十进制编译后会编译为十进制
  8. let myName:string = 'Joy'; // string
  9. // 可用 void 表示没有任何返回值的函数:
  10. // undefined 和 null 是所有类型的子类型, 可以赋值给所有类型, 但void不可以
  11. let u: undefined = undefined; // undefined
  12. let n: null = null; // null
  13. let num:number = undefined // --right--
  14. let num:number = void // --wrong--

任意值类型

任意值类型any允许被赋予任何类型的值;

  1. let anyNumber:any = 'seven';
  2. anyNumber = 7;

可以访问任意值的任何属性和方法,返回的类型也是任意值。
未声明的变量,识别为任意值类型:

  1. let something; // any
  2. something = 'seven';
  3. something = 7;

类型推论

定义变量时赋值,但没有指定类型,TS会依照类型推论的规则推断出一个类型。

  1. let something = 'seven';
  2. something = 7; // error报错

联合类型

联合类型表示变量取值可以为多种类型种的一种:

  1. let item: string|number = 10; // 赋值时,会根据类型推论的规则推断出一个类型
  2. item = 'seven';

只能访问联合类型共有的属性、方法:

  1. function getLength(item:string|number):number{
  2. return item.length;
  3. } // error, length不是string和number的共有方法

描述对象 - 接口

可用来约束对象的“形状”,若无可选属性、任意属性,则形状需保持一致,属性不多不少:

  1. interface Person{
  2. name: string;
  3. age: number;
  4. }
  5. let tom:Person = {
  6. name: 'Tom';
  7. age: 18;
  8. }
  9. // 可选属性:
  10. interface Person{
  11. name: string;
  12. age?: number; // 表示属性是可选的
  13. }
  14. let tom:Person = {
  15. name: 'Tom';
  16. }
  17. // 任意属性
  18. interface Person{
  19. name: string;
  20. [propName:string]: any; // 表示允许有一个任意属性
  21. }
  22. let tom:Person = {
  23. name: 'Tom';
  24. sex: 'man';
  25. }
  26. // 一旦定义了任意属性,则确定属性和可选属性的类型必须是任意属性的类型的子集;
  27. // 但有一种例外:number 类型的任意属性签名不会影响其他 string 类型的属性签名:
  28. // 但 string类型的任意属性会影响其它。
  29. // 可以定义任意属性为联合类型[propName:string]:string|number

只读属性

readonly定义只读属性,那么该属性只有初始化时可被赋值。

  1. interface Person{
  2. readonly id: number;
  3. age?: number;
  4. }
  5. let tom: person = {
  6. if: 89757;
  7. }
  8. tom.id = 1000; // error

注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候。

数组的类型

多种定义方式,很灵活。

「类型 + 方括号」表示法

数组的项中不允许出现其他的类型;

  1. let nums: number[] = [1,2,3,4]
  2. let list: any[] = ['one', 2, {}, [4,5]]

数组泛型

另一种表示方法;

  1. let nums: Array<number> = [1,2,3,4]

用接口表示数组

但通常不这么做;更多用来表示类数组。

  1. interface NumberArray{
  2. [index: number]: number;
  3. }
  4. let nums: NumberArray = [1,2,3,4]

类数组

不能用数组表示,应该用接口来表示

  1. interface IArguments{ // 这是TS定义好的类型
  2. [index: number]: any;
  3. length: number;
  4. callee: Function;
  5. }

函数的类型

JS中常见定义函数的两种方式:

  1. function sum(a, b){ return a+b; } // 函数声明
  2. let sum = function(a, b){ return a+b; } // 函数表达式

对应的TS类型定义为:

  1. // 函数声明,调用时,传入参数的个数需要正确
  2. function sum(a: number, b: number): number{ return a+b; }
  3. // 函数表达式
  4. let sum: (a:number,b:number)=>number = function (a:number, b:number):number{return a+b;}
  5. // 注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>

还可以用接口定义函数形状:

  1. interface SearchFunc {
  2. (source: string, subString: string): boolean;
  3. }
  4. let mySearch: SearchFunc;
  5. mySearch = function(source: string, subString: string) {
  6. return source.search(subString) !== -1;
  7. }

可选参数

如何定义可选参数,一种方法与接口的可选属性类似,使用”?”:

  1. function sum(a:number, b:number, c?:number): number{
  2. if(c !== undefined)return a+b+c;
  3. return a+b;
  4. }
  5. // 可选参数后面不允许再出现必需参数

参数默认值:TS会将添加了默认值的参数,识别为可选参数,这也是添加可选参数的另一种方法:

  1. function sum(a:number, b:number, c:number = 5): number{
  2. return a+b+c;
  3. }

剩余参数

ES6中使用...rest的方式获取函数的剩余参数,是一个数组,因此表示如下:

  1. function myPush(array:number[], ...rest:number[]){
  2. rest.forEach((item)=>{
  3. array.push(item);
  4. });
  5. }
  6. let a = [];
  7. myPush(a, 1, 2, 3, 4);

重载

重载表示函数接收参数数量或类型不同时,做出不同的处理。
如输入123,返回321;输入’one’,返回’eno’。

  1. // 使用联合类型实现,但有个缺点,即不能精确表达
  2. function myReverse(n: string | number): string | number {
  3. if (typeof n === 'number') {
  4. return Number(n.toString().split('').reverse().join());
  5. }
  6. else if (typeof n === 'string') {
  7. return n.split('').reverse().join();
  8. }
  9. }
  10. // 使用重载,对比联合也就在前面加了两行函数定义
  11. // TypeScript 会优先从最前面的函数定义开始匹配,所以优先将精确的定义放在前面
  12. function reverse(x: number): number;
  13. function reverse(x: string): string;
  14. function reverse(x: number | string): number | string {
  15. if (typeof x === 'number') {
  16. return Number(x.toString().split('').reverse().join(''));
  17. } else if (typeof x === 'string') {
  18. return x.split('').reverse().join('');
  19. }
  20. }

类型断言

语法:值 as 类型

断言的用途

  • 将一个联合类型断言为其中一个类型
  • 将一个父类断言为更加具体的子类
  • 将任何一个类型断言为 any:它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用 as any
  • any 断言为一个具体的类型
  • B兼容A或A兼容B,则可相互断言

    双重断言

    双重断言 as any as Foo,除非迫不得已,千万别用双重断言。

    类型断言VS类型转换

    类型断言不会影响到变量的类型

    类型断言VS类型声明

    类型断言VS泛型

    声明文件

    当你在编写TS代码时,需要使用第三方的JS库(.js文件),引入的时候编译器会提示各种报错,因为引用的JS文件没有各种声明,这时候就需要有一个声明文件来进行辅助,才能获得对应的代码补全、接口提示等功能。
    如:需引用module-lib.js文件,则需要在同目录下有module-lib.d.ts文件(TS会自动使用),很多第三方库都会提供自己的声明文件。

    内置对象

    很多JS内置对象都在TS定义好了类型。

    ECMAScript 的内置对象

    DOM 和 BOM 的内置对象

    TypeScript 核心库的定义文件

    用 TypeScript 写 Node.js

    需引入第三方声明文件:npm install @types/nodes--save-dev