文章目录

  • 1、TypeScript环境搭建
  • 1、安装TypeScript
  • 2、构建第一个TypeScript文件
  • 2、TypeScript中的类型声明
  • 3、TypeScript中基础类型
  • 1、布尔值
  • 2、数字
  • 3、字符串
  • 4、数组
  • 5、元组(Tuple)
  • 6、枚举(enum)
  • 7、Any
  • 8、Void
  • 9、Never
  • 10、object
  • 11、补充
  • 4、类(class)
  • 1、类
  • 2、继承
  • 3、公共,私有与受保护的修饰符


1、TypeScript环境搭建

1、安装TypeScript

通过npm(Node.js包管理器)来安装,在终端中输入:

npm -g install ts-node typescript

在VS Code 中安装如下插件:

TSLint、TypeScript Hero

2、构建第一个TypeScript文件

先在编辑器中创建一个以ts为后缀的文件 greeter.ts

function greeter(person) {
    return "Hello, " + person;
}

let user = "Jane User";

document.body.innerHTML = greeter(user);

编译代码,在命令行中运行(文件目录下):

tsc greeter.ts

我们可以看到结果输出了一个greeter.js文件

2、TypeScript中的类型声明

let a:number;
//a 的类型设置为number,在以后的使用过程过程中a的值只能是数字

a = 10;

// a = 'hello';
//此行代码会报错,因为变量a的类型时number,不能够赋值字符串

let b: string;
b = 'hello';
//b = 123;
//此行代码会报错,因为变量a的类型是string,不能够赋数字

//声明完变量直接进行赋值
// let c: boolean = false;

// 如果变量的声明和赋值时同时进行的,TS可以自动对变量进行类型检测
let c= false;

c = true;

//c = 123;
//此行代码会报错

//这个特性主要用到函数中
function sum(a,b){
    return a+b;
}
console.log(sum(123,456));//579
console.log(sum(123, "456"));//123456

//以上是在js中的函数写法,可以正常运行,但是我们可以对函数参数进行类型限定
function sum1(a: number, b: number){
    return a+b;
}

// sum1(133, "456")//类型出错
// sum(1233,1525,166)//数量出错

//我们也可以对函数的返回值的类型进行限定,在下面函数中,如果函数的返回值不是数字,就会出现报错
function sum(a: number, b:number): number{
    return a + b;
}

let result = sum(123, 456);

//可以使用 | 来连接多个类型(联合类型)
let b1: "male" | "female";
b1= "male";
b1= "female";

3、TypeScript中基础类型

类型

例子

描述

number

1, -33, 2.5

任意数字

string

‘hi’, “hi”, hi

任意字符串

boolean

true、false

布尔值true或false

字面量

其本身

限制变量的值就是该字面量的值

any

*

任意类型

unknown

*

类型安全的any

void

空值(undefined)

没有值(或undefined)

never

没有值

不能是任何值

object

{name:‘孙悟空’}

任意的JS对象

array

[1,2,3]

任意JS数组

tuple

[4,5]

元素,TS新增类型,固定长度数组

enum

enum{A, B}

枚举,TS中新增类型

1、布尔值

布尔值(boolean),其值为true/false

let isDone: boolean = false;

2、数字

TypeScript里的所有数字都是浮点数。 这些浮点数的类型是 number。 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量。

let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;

3、字符串

我们使用 string表示文本数据类型,使用双引号( ")或单引号(')表示字符串

let name: string = "bob";
name = "smith";

4、数组

有两种方式可以定义数组。 第一种,可以在元素类型后面接上 [],表示由此类型元素组成的一个数组:

let list: number[] = [1, 2, 3];

第二种方式是使用数组泛型,Array<元素类型>

let list: Array<number> = [1, 2, 3];

5、元组(Tuple)

元组表示一个固定长度和固定数组元素类型的特殊数组

/* 
    tuple(元组):就是固定长度的数组
        语法:[类型, 类型, 类型]
*/
let x: [string, number];
x = ['hello', 10];

6、枚举(enum)

枚举类型在javascript中不存在,这是TS对js标准数据类型的一个补充,使用枚举类型可以为一组数值赋予友好的名字

enum Color {Red, Green, Blue}
let c: Color = Color.Green;

0开始为元素编号。 你也可以手动的指定成员的数值

enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;
enum Gender{
    Male = 0,
    Female = 1,
}
let i: {name: string, gender: Gender};
i = {
    name: '孙悟空',
    gender: Gender.Male//'male'
}

console.log(i.gender === Gender.Male)

7、Any

any 表示的是任意类型,一个变量设置类型为any后相当于对该变量关闭了TS的类型检测

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

声明变量如果不指定类型,则TS解析器会自动判断变量的类型为any(隐式的any)

let d;
d = 10;
d = 'hello';
d = 'true';

unknown 实际上就是一个类型安全的any,unknown 类型的变量,不是直接赋值给其他变量

let e: unknown;
e = 10;
e = true;
e = "hello";

let s:string;
if (typeof e === "string") {
    s = e;   
}

8、Void

void 用来表示空,以函数为例,就表示没有返回值得函数

function warnUser(): void {
    console.log("This is my warning message");
}

9、Never

never类型表示的是那些永不存在的值的类型。 例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
    while (true) {
    }
}

10、object

let a:object;
a = {};
a = function(){

};

//{ } 用来指定对象中可以包含哪些属性
//语法:{属性名:属性值,属性名:属性值}
//在属性名后面加上?,表示属性是可选的
let b: {name: string, age?:number};
b = {name: "孙悟空", age: 18};

//[propName: string]:any 表示任意类型的属性
let c: {name: string, [propName: string]:any}

c = {name:"猪八戒", age: 18, gender: '男'}

/* 
    设置函数结构的类型声明:
        语法: (形参:类型,形参:类型...)=> 返回值
*/
let d1: (a:number ,b: number)=>number;

d1 = function (n1: number, n2: number): number {
    return n1 + n2
}

11、补充

类型断言: 可以用来告诉解析器变量的实际类型

/*
语法:
    变量 as 类型
    <类型>变量
*/
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

4、类(class)

1、类

//利用class关键字声明一个 Greeter 类
class Greeter {
    greeting: string;//一个叫做 greeting的属性,可以在这里定义属性的数据类型
    constructor(message: string) {//构造函数,用于初始化
        this.greeting = message;
    }
    greet() {//一个 greet 方法
        return "Hello, " + this.greeting;
    }
}

let greeter = new Greeter("world");

2、继承

类从基类中继承了属性和方法,通过 extends关键字实现继承,在构造函数里访问 this的属性之前,我们一定要调用 super()

class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

class Snake extends Animal {//通过 extends 关键字实现继承
    constructor(name: string) { super(name); }//在构造函数中通过super关键字调用父类的构造函数
    go(distanceInMeters = 5) {//子类当中定义的自己的方法
        console.log("Slithering...");
        super.move(distanceInMeters);//通过super方法可以调用父类的方法
    }
}

let sam = new Snake("Sammy the Python");

sam.go();
sam.move();

3、公共,私有与受保护的修饰符

默认为 public,在TypeScript里,成员都默认为 public

class Animal {
    public name: string;
    public constructor(theName: string) { this.name = theName; }
    public move(distanceInMeters: number) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

当成员被标记成 private时,它就不能在声明它的类的外部访问。比如:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

new Animal("Cat").name; // 错误: 'name' 是私有的.

protected修饰符与 private修饰符的行为很相似,但有一点不同, protected成员在派生类中仍然可以访问。构造函数也可以被标记成 protected。 这意味着这个类不能在包含它的类外被实例化,但是能被继承

class Person {
    protected name: string;
    protected constructor(name: string) { this.name = name; }
}

class Employee extends Person {
    private department: string;

    constructor(name: string, department: string) {
        super(name)
        this.department = department;
    }

    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;
    }
}

let howard = new Employee("Howard", "Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); // 错误

可以使用 readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。

class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor (theName: string) {
        this.name = theName;
    }
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的.

TypeScript支持通过getters/setters来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。

//getter和setter
class MyInfo { //class是关键字,类名默认全部大写首字母
  private readonly _name: string; //私有属性,外部不可访问。readonly使其只能在初始化时赋值,以后不可更改。    
  private _weather: string; //私有属性,习惯以_开头进行命名

  constructor(name: string, weather: string){ //构造函数,一般用于初始化
    this._name = name;
    this._weather = weather;
  }
  get name(): string {
    return this._name;
  }
  set name(value: string) {  //error! _name有readonly属性
    this._name = value;
  }
  get weather(): string {
    return this._weather;
  }
  set weather(value: string) {
    this._weather = value;
  } 
}
  
let myData = new MyInfo('QiGe', 'raining'); //使用new关键字生成对象
console.log(myData.name, myData.weather);
myData.weather = 'sunny'; //OK
myData.name = 'Wang'; //error!
console.log(myData);

创建类的静态成员,这些属性存在于类本身上面而不是类的实例上,就是说我们可以直接通过类来调用这些成员,而不用实例化类。

class Grid {
    static origin = {x: 0, y: 0};//通过static关键字声明静态属性
    calculateDistanceFromOrigin(point: {x: number; y: number;}) {
        let xDist = (point.x - Grid.origin.x);//静态属性通过类名来直接调用
        let yDist = (point.y - Grid.origin.y);
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }
    constructor (public scale: number) { }//把声明和赋值合并至一处
    /*
    //上面一行代码写完整是如下
    public scale:number;
    constructor(theScale:number){
    this.scale = theScale;
    }
    */
}

let grid1 = new Grid(1.0);  // 1x scale
let grid2 = new Grid(5.0);  // 5x scale

console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));