TypeScript 入门教程

一、介绍

TypeScript 是 JavaScript 的超集(超集表示前者包含了后者),扩展了 JavaScript 的语法。TypeScript 无法直接运行于浏览器上,需要编译转换成 JavaScript 才可以在浏览器上运行。

二、优缺点

  1. 优点

    • 通过静态类型检测,可以在编译期把很多 bug 暴露出来,借助 IDE 可以在编码时实时发现编码错误,提高代码的健壮性。
    • 方便重构代码,在编译时就可以发现重构时出现的问题,然后及时修复。借助 IDE 可以在重构时实时看到受影响的所有文件及代码,方便及时修复。
  2. 缺点

    • 需要手写很多类型定义,需要编译完才能在浏览器上运行。

三、安装

  1. 先安装 node(安装方法自己网上找),然后通过 node 携带的 npm 来安装 TypeScript;

  2. npm 安装 TypeScript 的命令如下:

    npm install -g typescript
    
  3. 安装完成后,可以通过执行命令 tsc -v 检查安装是否成,执行命令后显示版本号即表示安装成功。

    tsc -v
    # Version 3.2.2
    
  4. 通过执行以下命令将 TypeScript 转换成 JavaScript 。(通常我们使用 .ts 作为 TypeScript 代码文件的扩展名)

    tsc test.ts
    

    执行上面命令后,会在当前目录下生成转换后的 test.js 文件。

四、数据类型

TypeScript 包含的数据类型如下:

数字类型 number、字符串类型 string、布尔类型 boolean、数组类型、元组类型、泛型类型、枚举类型 enum、任意类型 any、null、undefined、void、nerver

用法如下:

// 数字类型(number)
let n: number = 10;

// 字符串类型(string)
let str: string = "张三";

// 布尔类型(boolean)
let b: boolean = true;

// 数组类型,这有两种方法
let arr1: string[] = ["张三", "李四", "王五"];
let arr2: Array<string> = ["张三", "李四", "王五"];

// 元组类型,
let arr: [number, string] = [10, '张三'];

// 泛型类型
interface Hello<T> {
    (arg: T): T;
}
function myHello<T>(arg: T): T {
    return arg;
}

// 枚举类型(enum)
enum Flag{ 
    success, 
    error
}
let f: Flag = Flag.success;
console.log(f);// 0

// 任意类型
let x: any = 1;    // 数字类型
x = '张三';    // 字符串类型
x = false;    // 布尔类型
let arrayList: any[] = [1, false, 'fine'];
arrayList[1] = 100;

//当一个元素可能是null,可能是undefined,可能是number
let num: number| null | undefined;
num = 123;
num = null;
num = undefined;

// void一般只用于定义函数的时候用
function run1(): void {
    console.log('打印');
}
function run2(): number {
    return 123;
}

// never的函数可以是抛出异常的情况
function error(message: string): never {
    throw new Error(message);
}

// never的函数可以是无法被执行到的终止点的情况
function loop(): never {
    while (true) {}
}

五、类型断言

类型断言可以用来手动指定一个值的类型,即允许变量从一种类型更改为另一种类型。

语法格式: <类型> 值 或者 值 as 类型

实例:

let str = '1';
let num: number = <number> <any> str;

六、类型推断

当类型没有给出时,TypeScript 编译器利用类型推断来推断类型。

let num = 2;    // 类型推断为 number
num = "12";    // 编译错误

七、函数

实例:

// 固定参数
function buildName1(firstName: string, lastName: string) {
    return firstName + " " + lastName;
}
buildName1("Bob"); // 错误,缺少参数
buildName1("Bob", "Adams", "Sr."); // 错误,参数太多了
buildName1("Bob", "Adams"); // 正确

// 可选参数
function buildName2(firstName: string, lastName?: string) {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}
buildName2("Bob"); // 正确
buildName2("Bob", "Adams", "Sr."); // 错误,参数太多了
buildName2("Bob", "Adams"); // 正确

// 剩余参数
function buildName3(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}
buildName3("Joseph", "Samuel", "Lucas", "MacKinzie");

// 默认参数
function calculate_discount(price: number, rate: number = 0.50) { 
    let discount = price * rate; 
    return discount;
} 
calculate_discount(1000);
calculate_discount(1000, 0.30);

八、接口

接口是一系列抽象方法的声明,这些方法都应该是抽象的,需要由具体的类去实现。

实例:

interface IPerson { 
    firstName: string, 
    lastName: string, 
    sayHi: () => string 
} 
 
let customer: IPerson = { 
    firstName: "Tom",
    lastName: "Hanks", 
    sayHi: (): string => {return "Hi there"} 
}

接口和数组:

interface namelist { 
   [index: number]: string 
} 
 
let list2: namelist = ["John", 1, "Bran"] // 错误,元素 1 不是 string 类型

接口继承:

// 单继承
interface Person { 
   age: number 
} 
 
interface Musician extends Person { 
   instrument: string 
} 
 
let drummer = <Musician>{}; 
drummer.age = 27;
drummer.instrument = "Drums";

// 多继承
interface IParent1 { 
    v1: number 
} 
 
interface IParent2 { 
    v2: number 
} 
 
interface Child extends IParent1, IParent2 {} 

let obj: Child = {v1: 12, v2: 23} 

九、类

类描述了所创建对象的共同属性和方法。

实例:

class Car { 
   // 字段
   engine: string; 
   
   // 构造函数
   constructor(engine: string) { 
      this.engine = engine;
   }  
   
   // 方法
   disp(): void { 
      console.log("函数中显示发动机型号  :   "+this.engine) 
   } 
} 
 
// 创建一个对象
let obj = new Car("XXSY1")
 
// 访问字段
console.log("读取发动机型号 :  " + obj.engine);  
 
// 访问方法
obj.disp();

类继承:

class Shape { 
   Area: number;
   
   constructor(a: number) { 
      this.Area = a; 
   } 
} 
 
class Circle extends Shape { 
   disp(): void { 
      console.log("圆的面积:  " + this.Area);
   } 
}
  
let obj = new Circle(223); 
obj.disp();

static 关键字:用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。

class StaticMem {  
   static num: number; 
   
   static disp(): void { 
      console.log("num 值为 " + StaticMem.num);
   } 
} 
 
StaticMem.num = 12; // 初始化静态变量
StaticMem.disp(); // 调用静态方法

访问修饰符:

  • public(默认):公有,可以在任何地方被访问。
  • protected:受保护,只能被其自身以及其子类访问。
  • private:私有,只能被其定义所在的类访问。
class Encapsulate { 
   str1: string = "hello";
   private str2: string = "world";
}
 
let obj = new Encapsulate();
console.log(obj.str1); // 可访问 
console.log(obj.str2); // 编译错误,str2 是私有的

类实现接口:

interface ILoan { 
   interest: number
} 
 
class AgriLoan implements ILoan { 
   interest: number; 
   rebate: number;
   
   constructor(interest: number, rebate: number) { 
      this.interest = interest;
      this.rebate = rebate;
   } 
} 
 
let obj = new AgriLoan(10, 1);

十、命名空间

命名空间一个最明确的目的就是解决重名问题。

  1. TypeScript 中命名空间使用 namescape 来定义,语法格式如下:
namespace SomeNameSpaceName { 
   export interface ISomeInterfaceName {      }  
   export class SomeClassName {      }  
}

以上定义了一个命名空间 SomeNameSpaceName,如果我们需要在外部可以调用 SomeNameSpaceName 中的类和接口,则需要在类和接口添加 export 关键字。调用方法如:SomeNameSpaceName.SomeClassName;

如果一个命名空间在一个单独的 TypeScript 文件中,则应使用三斜杠 /// 引用它,语法格式如下:

/// <reference path = "SomeFileName.ts" />
  1. 以下实例演示了命名空间的使用,定义在不同文件中:

IShape.ts 文件:

namespace Drawing { 
    export interface IShape { 
        draw(); 
    }
}

Circle.ts 文件:

/// <reference path = "IShape.ts" /> 
namespace Drawing { 
    export class Circle implements IShape { 
        public draw() { 
            console.log("Circle is drawn"); 
        }  
    }
}

Triangle.ts 文件:

/// <reference path = "IShape.ts" /> 
namespace Drawing { 
    export class Triangle implements IShape { 
        public draw() { 
            console.log("Triangle is drawn"); 
        } 
    } 
}

TestShape.ts 文件:

/// <reference path = "IShape.ts" />   
/// <reference path = "Circle.ts" /> 
/// <reference path = "Triangle.ts" />  
function drawAllShapes(shape: Drawing.IShape) { 
    shape.draw(); 
} 
drawAllShapes(new Drawing.Circle());
drawAllShapes(new Drawing.Triangle());
  1. 嵌套命名空间

Invoice.ts 文件:

namespace Runoob { 
   export namespace invoiceApp { 
      export class Invoice { 
         public calculateDiscount(price: number) { 
            return price * .40; 
         } 
      } 
   } 
}

InvoiceTest.ts 文件:

/// <reference path = "Invoice.ts" />
let invoice = new Runoob.invoiceApp.Invoice(); 
console.log(invoice.calculateDiscount(500));

十一、类型定义

我们可以使用 type 用来定义类型变量:

// 基本类型
type UserName = string

// 类型赋值
type WebSite = string | undefined
type Tsaid = WebSite

// 对象
type User = {
  name: string;
  age: number;
  website: WebSite;
}

// 方法
type say = (age: number) => string

// 类型遍历 in
type ChinaMobilePhones = '10086' | '10010' | '10000'

type ChinaMobile {
  name: string;
  website: string;
}

type ChinaMobileList = {
  [phone in ChinaMobilePhones]: ChinaMobile
}

当然,我们也可以使用 interface 定义我们的复杂类型,在 TypeScript 中我们也可以直接定义 interface:

interface Application {
    init(): void
    get(key: string): object
}

interface 和 type 很像。但是 type 的含义是定义自定义类型,当 TypeScript 提供给你的基础类型都不满足的时候,可以使用 type 自由组合出你的新类型,而 interface 应该是对外输出的接口。type 不可以被继承,但 interface 可以。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值