TypeScript看完就会了

TypeScript
什么是TypeScript?
TypeScript是由微软开发的一款开源的编程语言
TypeScript是JavaScript的超集,遵循最新的ES5 ES6规范,TypeScript扩展了JavaScript的语法
TypeScript更像后端 Java c# 这样的面向对象语言可以让js开发大型企业项目
谷歌也在大力支持TypeScript的推广,React ,VUE 都集成了TypeScript
TypeScript安装
安装

-- 安装
npm install -g typescript

检查是否安装成功 
tsc -v 
1
2
3
4
5
编译

-- 将.ts文件转换成.js文件
tsc 文件名.ts
1
2
VsCode配置TypeScript
vscode配置TypeScript文件自动编译

在.ts文件夹下运行cmd 执行 tsc --init 命令 自动生成tsconfig.json配置文件

更改tsconfig.json配置文件 “outDir”: “./js”,编译后js输出的目录

任务 ——>运行任务 ——> 监视tsconfig.json 文件


vscode监视tsconfig报错
1.管理员身份运行vs code

2.在终端执行:get-ExecutionPolicy,显示Restricted

3.在终端执行:set-ExecutionPolicy RemoteSigned

4.在终端执行:get-ExecutionPolicy,显示RemoteSigned

1
2
3
4
5
6
7
8
数据类型
TypeScript中为了使编写的代码更规范,更利于维护,增加了类型校验,在声明变量同时为它指定数据类型

格式 : 变量名: 数据类型 = 值

布尔类型(boolean)
// 布尔类型(boolean) 
let flag:boolean = false;
console.log(flag);
1
2
3
数值类型(number)
// 数值类型(number)
let num:number = 20;
console.log(num);

// 如果没有值不是number类型那么ts编译会报错 但是浏览器可以正常输出
// let num1:number = "20";
// console.log(num1);
1
2
3
4
5
6
7
字符串类型(string)
// 字符串类型(string)
let str:string = "Hello";
console.log(str);
1
2
3
数组类型(Array)
// 数组类型(Array) 直接为数组的每个元素指定同一类型

// 数组声明方式一  数组声明时指定 数组类型
let arr:number[] = [1,2,3,4];
console.log(arr);

// 数组声明方式二  Array数组类型 给它指定泛型
let arr1:Array<string> = ["1","2","3"];
console.log(arr1);

// 数组声明方式三 any类型
let arr2:any[] = ["this","me"];
console.log(arr2);
1
2
3
4
5
6
7
8
9
10
11
12
13
元组类型(tuple)
// 元组类型(tuple) 属于数组的一种 为数组的每一个元素指定一个类型
let arr3:[string,number,boolean] = ["this",1,true];
console.log(arr3);
1
2
3
枚举类型(enum)
// 枚举类型(enum)
/* 
    声明方式
    enum 枚举名{
        标识符=[值]
    }
*/

enum Color{
    red,
    blue,
    yellow="yellow"
}
// 如果枚举没有给枚举元素赋值那么指向的是当前元素的下标
console.log(Color.blue);
// 给枚举元素赋值 直接输出当前元素的值
let y:Color = Color.yellow;
console.log(y);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
任意类型(any)
// 任意类型(any) 可以随意指定类型
let sum:any = 123;
sum = "456";
console.log(sum);

1
2
3
4
5
null和undefined
// null和undefined 其他类型(never类型)数据类型的子类型
// 声明未赋值 undefined
let str1:string;
console.log(str1); // 输出 undefined 但是 ts编译会报错

// 指定string 或 undefined 如果不赋值 输出undefined编译不会出错
let str2: string | undefined = "Hello";
console.log(str2);

// null 类型 只能为null
let str3:null = null;
console.log(str3);

// 为一个元素指定多种类型
let str4:string | undefined | null;
str4 = "Hello";
console.log(str4);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void类型
// void类型 :typescript中的void表示没有任何类型,一般用于定义函数的时候函数没有返回值
// 指定foo函数没有返回值
function foo():void{
    console.log("void");
}
foo();

// 指定函数返回值类型
function get():number{
    return 100;
}
console.log(get());

1
2
3
4
5
6
7
8
9
10
11
12
13
never类型
// never类型:是其他类型(包括null,undefined)的子类型,代表从来不会出现的值,
// 这意味着never声明的变量只能被never类型所赋值
var a:undefined;
a = undefined;
console.log(a);

var b:null;
b = null;
console.log(b);

// 从未出现的值  一般never类型不常用
var err:never;
err = (()=>{throw new Error("Error")})();


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
函数
函数定义
// 函数定义
// 定义无返回值
function fun():void{
    console.log("void")
}
fun();

const fun1 = function():void{
    console.log("字面量函数void")
}
fun1();

// 定义带返回值的函数
function fun2():string{
    return "返回值类型是string";
}
console.log(fun2());

const fun3 = function():string{
    return "字面量函数带返回值";
}
console.log(fun3());

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
函数参数
// 函数参数 在参数后面指定参数的类型
function fun4(name:string){
    return name;
}
console.log(fun4("小牛"));

1
2
3
4
5
6
可选参数
// 可选参数  
// 有时候需要age这个参数 有时候不需要 我们可以给age设置可选
function fun5(name:string,age?:number):any{
    // 如果有age这个参数 我们返回 name 和 age
    if(age){
        return `${name} --- ${age}`;
    }
    // 如果没有我们只返回name
    return `${name}`;
}
console.log(fun5("牛小牛",22));

// 注意:可选参数尽量写在形参列表最后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
认参数
// 认参数  
// 在参数定义时给它赋上认值 
function fun6(name:string,age:number=20):any{
    return `${name}---${age}`;
}
console.log(fun6("小牛",21));

1
2
3
4
5
6
7
剩余参数
// 剩余参数 ... 用于参数列表不确定参数个数使用
// 注意:剩余参数写在形参列表最后
function fun7(a:number,...result:number[]){
    let num:number = a;
    for(let v of result){
        num += v;
    }
    return num;
}
console.log(fun7(1,4,5));

1
2
3
4
5
6
7
8
9
10
11
函数重载
// 函数重载 ts支持函数重载
// 函数重载 : 函数名相同参数列表不同(参数的个数,顺序,类型)有一个不同就都不相同
function getInfo(name:string):string;
function getInfo(age:number):number;
function getInfo(str:any):any{
    if(typeof str === "string"){
        return str;
    }else{
        return str;
    }
}
console.log(getInfo("hello"))

// 多个参数重载
function getData(name:string):string;
function getData(name:string,age:number):any;
function getData(name:string,age?:number):any{
    if(age){
        return `${name} --- ${age}`;
    }
    return `${name}`
}
console.log(getData("小牛",22));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
箭头函数
// 箭头函数 es6箭头函数一样
setTimeout(()=>console.log("箭头函数的this依然指向上下文"));

1
2
3

ES5类
 // es5类

    // 最简单的类
    function Student(){
        this.name = "小牛";
        this.age = 20;
    }
    const s = new Student();
    console.log(s.name);

    console.log("-----------------------")

    // 构造函数和原型链上增加方法
    function Person(){
        this.name = "小牛";
        this.age = 21;
        this.run = function(){
            console.log(this.name + "在运动");
        }
    }
    // 原型链上的属性会被多个实例共享 构造方法不会
    Person.prototype.sex = "man";
    Person.prototype.work = function(){
        console.log(this.name + "在工作");
    }
    var p = new Person();
    console.log(p.name);
    p.run();
    p.work();

    console.log("-----------------------")


    // 类里面的静态方法
    function Stu(){
        this.name = "小牛"; // 属性
        this.age = 21;
        this.run = function(){ // 实例方法
            console.log(this.name + "在运动");
        }
    }
    // 静态方法只能被类调用 不能被实例调用
    Stu.getInfo = function(){
        console.log("我是静态方法")
    }
    // var stu = new Stu();
    // stu.getInfo();
    // 类 调用静态方法
    Stu.getInfo();

    console.log("-----------------------")

    // 冒充继承
    function Girl(){
        this.name = "MM";
        this.age = 20;
        this.run = function(){
            console.log(this.name + "运动")
        }
    }
    // 原型链
    Girl.prototype.color = "pink";
    Girl.prototype.work = function(){
        console.log(this.name + "工作")
    }

    // Web类 继承Girl类 原型链 + 冒充继承
    function Web(){
        // 对象冒充继承 call apply bind
        Girl.call(this);
    }
    var w = new Web();
    // 冒充继承可以继承构造函数属性方法
    w.run();
    // 冒充继承可以继承构造函数中的属性方法 但是不能继承原型链的属性方法
    // w.work(); 
    console.log("-----------------------")

    //  原型链实现继承 继承Girl类

    function Father(){
        this.name = "牛小牛";
        this.age = 22;
        this.run = function(){
            console.log(this.name + "运动");
        }
    }
    Father.prototype.work = function(){
        console.log(this.name + "工作")
    }


    function Man(){

    }
    // 原型链继承 可以继承构造函数属性方法,也可以继承原型链上的属性方法
    Man.prototype = new Father();
    var m = new Man();
    console.log(m.age);
    m.run();
    m.work();

    console.log("-----------------------")

    // 原型链继承的问题?
    function F(name,age){
        this.name = name;
        this.age = age;
        this.run = function(){
            console.log(this.name + "运动")
        }
    }
    F.prototype.sex = "man";
    F.prototype.work = function(){
        console.log(this.name + "工作")
    }
    var f = new F("花花牛",21);
    f.work();

    function FF(name,age){

    }
    FF.prototype = new F();
    var ff = new FF("雨花雨",21);
    // 原型链继承传参的问题
    ff.run();

    console.log("-----------------------")


    // 原型链 + 冒充继承组合继承模式
    function P(name,age){
        this.name = name;
        this.age = age;
        this.run = function(){
            console.log(this.name + "运动")
        }
    }
    P.prototype.sex = "man";
    P.prototype.work = function(){
        console.log(this.name + "工作")
    }
    function PP(name,age){
        P.call(this,name,age);
    }
    PP.prototype = new P();
    var pp = new PP("雨花雨",22);
    pp.run();
    pp.work();

    console.log("-------------------------")

    // 原型链 + 冒充继承的另一种方式

    function Man(name,age){
        this.name = name;
        this.age = age;
        this.run = function(){
            console.log(this.name + "运动")
        }
    }
    Man.prototype.sex = "man";
    Man.prototype.work = function(){
        console.log(this.name + "工作")
    }
    function M(name,age){
        Man.call(this,age);
    }
    M.prototype = Man.prototype;
    var m = new M("奶牛",21);
    m.run();
    m.work();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
ES6类
  // 类的声明
    class Person{
        // 构造函数
        constructor(name,age) { 
            this.name = name;
            this.age = age;
        }
        // 定义方法
        show(name){
            console.log(this.name + "显示")
        }
    }
    let p = new Person("小牛",21);
    console.log(p.name);
    console.log(p.age);
    p.show();

    console.log("------------------------------")

    // 静态成员
    class Phone{
        // static 修饰的属性方法都是静态的只属于类
        static name = "Phone";
        static show(){
            console.log("静态方法")
        }
    }
    // 静态成员不能被实例化
    console.log(Phone.name);
    Phone.show();

    console.log("------------------------------")

    // 继承 extends super
    class A{
        constructor(name,age){
            this.name = name;
            this.age = age;
        }
        eat(){
            console.log("吃饭")
        }
    }

    class B extends A{
        constructor(name,age,color,size){
            super(name,age);
            this.color = color;
            this.size = size;
        }
        // 重写父类方法
        eat(){
            console.log("吃晚饭")
        }
    }
    const b = new B("小牛",20,"skyblue",180);
    console.log(b.name);
    b.eat();

    console.log("------------------------------")


    // get set 方法 
    class Smart{
        // 用来获取属性方法
        get price(){
            return "get方法获取属性"
        }
        // set 的时候 需要传入一个参数
        set price(newValue){
            console.log("set方法设置了属性")
        }
    }
    const smart = new Smart();
    smart.price = "set方法设置";
    console.log(smart.price)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
TS类的声明
// ts 类的声明
class Person{
    name:string;  // 属性 认public修饰 
    age:number;
    constructor(name:string,age:number){ // 构造函数 实例化的时候触发
        this.name = name;
        this.age = age;
    }
    show():void{
        console.log(this.name + "ts类中的方法")
    }
}
const person = new Person("小牛",21);
console.log(person.name);
console.log(person.age);
person.show();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
类的get set方法
get 和 set方法用于获取和设置类的属性

// 类的get set方法
class Student{
    name:string;
    constructor(name:string) {
        this.name = name;
    }
    // 用来设置属性的值
    setName(name:string):void{
        this.name = name;
    }
    // 用来获取属性的值
    getName():string{
        return this.name;
     }
}
const student = new Student("大牛");
// 获取没有设置之前的值
console.log(student.getName());
// 设置值
student.setName("二牛")
// 获取设置之后的值
console.log(student.getName());


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
继承
继承使用关键字extends,调用父类使用super,子类继承父类属性方法,并且子类可以改写父类属性方法

// 类的继承 extends super
class Phone{
    brand:string;
    price:number;
    constructor(brand:string,price:number){
        this.brand = brand;
        this.price = price;
    }
    show():void{
        console.log("Phone.show");
    }
}
class SmartPhone extends Phone{
    color:any;
    size:any;
    constructor(brand:string,price:number,color:any,size:any){
        super(brand,price);
        this.color = color;
        this.size = size;
    }
    // 重写父类方法
    show():any{
        console.log("SmartPhone.show")
    }
}
const smartPhone = new SmartPhone("iphoneX",7999,"black",5.5);
console.log(smartPhone.brand);
console.log(smartPhone.price);
console.log(smartPhone.color);
console.log(smartPhone.size);
smartPhone.show();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
访问修饰符
typescript为我们提供了三种访问修饰符

public 公共的 作用范围 本类 子类 类外部

protected*保护的 作用范围 本类 子类

​ private 私有的 作用范围 本类

// 访问修饰符
/*
    public 公共的  作用范围  本类 子类 类外部
    protected 保护的  作用范围  本类 子类 
    private 私有的  作用范围  本类
*/ 

class School{
    public name:string;
    protected age:number;
    private sex:string;
    constructor(name:string,age:number,sex:string){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    show():any{
        console.log("public---->" + this.name)
        console.log("protected---->" + this.age)
        console.log("private---->" + this.sex)
    }
}
const school = new School("xiaoniu",21,"man");
console.log(school.name);
school.show();
// age sex 分别是用 protected  private 在类外部不能访问所以编译出错
// console.log(school.age);
// console.log(school.sex);
class Teacher extends School{
    constructor(name:string,sex:string){
        super(name,sex);
    }
    show():any{ 
        console.log("public---->" + this.name)
        console.log("protected---->" + this.age)
        // sex 是private修饰的 继承过来的 sex是无法访问的所以会报错
        console.log("private---->" + this.sex)
    }
}
const teacher = new Teacher("daniu",22,"sex");
console.log(teacher.name);
teacher.show();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
静态成员
static修饰的静态成员当类加载时就存在 只能被类调用 不能实例化

// 静态成员
// 静态成员当类加载时就存在 不能被实例化
class Per {
    public name:string;
    public age:number;
    // static声明 静态属性
    static sex:any = "man";
    constructor(name:string,age:number) {
        this.name = name;
        this.age = age;
    }
    static eat():void{
        console.log("静态方法")
    }
}
const p = new Per("小牛",21);
console.log(p.name)
// 静态成员只能被类调用
console.log(Per.sex)
Per.eat();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
多态
多态 :父类定义方法不一定实现,让继承它的子类去实现,每个子类都有不同的表现形式

class Animal{
    public name:string;
    constructor(name:string){
        this.name = name;
    }
    eat(){
        console.log("吃的方法!")
    }
}
class Dog extends Animal{
    constructor(name:string){
        super(name);
    }
    eat(){
        console.log(this.name + "吃骨头")
    }
}
const dog = new Dog("小狗狗");
dog.eat();

class Cat extends Animal{
    constructor(name:string){
        super(name);
    }
    eat(){
        console.log(this.name + "吃猫粮")
    }
}
const cat = new Dog("小花猫");
cat.eat();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
抽象类
typescript中的抽象类:它是提供其他类继承的基类,不能被直接实例化

abstract 关键字修饰的抽象类和抽象方法, 抽象类中的抽象方法不包含具体的实现并且必须在派生类中实现

abstract 修饰的方法只能在抽象类中

// 抽象类
abstract class Animal {
    public name:any;
    constructor(name:any){
        this.name = name;
    }
    abstract eat():any;
    // 非抽象方法 子类可以不实现它
    say(){
        console.log(this.name + "在说话")
    }
}

class Dog extends Animal{
    constructor(name:any){
        super(name);
    }
    // 抽象类的子类必须实现抽象类的抽象方法
    eat(){
        console.log(this.name + "吃骨头")
    }
}

class Cat extends Animal{
    constructor(name:any){
        super(name);
    }
    eat(){
        console.log(this.name + "吃猫粮")
    }
}
const cat = new Cat("小花猫");
cat.eat();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
接口
接口:是一种规范的定义,它定义了行为和动作的规范,接口起到了一种限制和规范的作用,接口定义了某一批类所需要的遵循的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法实现的细节,它只规定了这批类必须提供某些方法,提供了这些方法的类就可以满足实际需要,typescript中的接口类似于java,同时还增加了更灵活的接口属性包括属性函数,可索引和类等。

json约束
约束了json的格式

// 接口 interface

interface Conn{
    host:string;
    port:number;
    username:string;
    password:string
}

// 约束了参数 及参数类型
function Connection(info:Conn):any{
    return `${info.host} --- ${info.port} --- ${info.username} --- ${info.password}`;
}
// 第一种传参方式
 Connection({
     host:"localhost",
     port:3306,
     username:"root",
     password:"root"
 })

const conn = {
    host:"localhost",
    port:3306,
    username:"root",
    password:"root"
}

// 第二种传参方式
console.log(Connection(conn))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
可索引接口
可索引接口用来约束数组的格式

// 可索引接口 约束数组
interface Arr{
    // 约束数组 下标为number类型 的一个string类型数组
    [index:number]:string;
}
const ones:Arr = ["A","B","C"];
console.log(ones[0])


1
2
3
4
5
6
7
8
9
对象约束
// 对象的约束
interface Obj{
    [key:string]:any
}
const obj:Obj = {"name":"小牛"}
console.log(obj["name"])

1
2
3
4
5
6
7
可选操作符
属性?:数据类型

表示可选 可以写也可以不写 可以通过编译

interface IPerson{
    firstName:string,
    // ? 可选操作符 
    lastName?:string,
    sayHi:()=>string
}
// 接口约束对象
const customer:IPerson = {
    firstName:"Tom",
    lastName:"Tim",
    sayHi:():string=> "Hi Tom"
}
console.log(customer);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
类类型接口
// 类类型接口  约束类
interface Cla{
    name:string;
    eat():any;
}

// 类类型接口  类只能用 implements 实现
class Birage implements Cla{
    public name = "goods";
    eat(){
        console.log("吃东西")
    }
}
const br = new Birage();
console.log(br.name)
br.eat();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
联合类型和接口
// 联合类型和接口
interface Runoptions{
    program:string;
    commandline:string[] | string | (()=>string);
}
const options:Runoptions = {
    program:"tim",
    
    // 参数可以是字符串数组
    // commandline:[
    //     "小牛",
    //     "大牛"
    // ]

    // 参数可以使字符串
    // commandline:"Hi"

    // 参数可以是箭头函数
    commandline:()=>"Hi Tim"
}
console.log(options.program)
console.log(options.commandline)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
接口封装ajax
// 封装ajax
interface Config{
    type:string;
    url:string;
    data?:string;
    dataType:string
}

function Ajax(config:Config):any{
    const xhr = new XMLHttpRequest();

    // 创建连接
    xhr.open(,config.type,config.url);

    // 发送请求
    xhr.send();

    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4 && xhr.status == 200){
            console.log("成功")
            if(config.dataType == "json"){
                console.log(JSON.parse(xhr.responseText))
            }else{
                console.log(xhr.responseText)
            }
        }
    } 
}
Ajax({
    url:"http://localhost:8080/heroall",
    type:"get",
    dataType:"json"
})


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
函数类型接口
函数类型接口:对方法传入的参数以及返回值进行约束

// 函数类型接口

interface encrypt{
    // 没有函数体 
    (Key:string,value:string):string;
}

var md5 = function(Key:string,value:string):string{
    return Key + "<--->" + value; 
}
console.log(md5("root","root"))

1
2
3
4
5
6
7
8
9
10
11
12
接口继承
接口可以继承另一个接口来扩展自己

// 接口继承  接口可以通过其他接口来扩展自己
interface Andy{
    eat():void;
}
interface anfn extends Andy{
    work():void;
}
class Program{
    age:number;
    constructor(age:number){
        this.age = age;
    }
    coding():void{
        console.log(this.age + "年龄加载")
    }
}
class Aniy extends Program implements anfn{
    name:string;
    constructor(age:number,name:string){
        super(age);
        this.name = name;
    }
    eat():void{
        console.log(this.name + "吃东西")
    }
    work():void{
        console.log(this.name + "工作")
    }
}
const aniy = new Aniy(20,"小牛");
aniy.coding();
aniy.eat();
aniy.work();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
泛型
泛型:软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)

泛型函数
// 泛型拯救了 any  泛型可以支持不特定的数据类型
// T 代表泛型 
function getDatas<T>(value:T):T{
    return value;
}
console.log(getDatas<number>(123));
console.log(getDatas<string>("小牛"));


1
2
3
4
5
6
7
8
9
泛型类
// 泛型类
class MinClass<T>{
    public list:T[] = [];

    add(value:T){
        this.list.push(value);
    }

    min():T{
        var minNum = this.list[0];
        for(let i=0;i<this.list.length;i++){
            if(minNum>this.list[i]){
                minNum = this.list[i];
            }
        }
        return minNum;
    }
}
// 实例化传入的 number类型决定了 他真正的类型
var m1 = new MinClass<number>();
m1.add(1);
m1.add(2);
m1.add(3);
m1.add(4);
console.log(m1.min())

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
泛型接口
// 泛型接口
// 函数型接口泛型
interface ConfigFn{
    <T>(value:T):T;
}
var getFn:ConfigFn = function<T>(value:T):T{
    return value;
}
getFn<number>(1);

// 泛型接口
interface getData2<T>{
    (value:T):T;
}
var getData2 = function<T>(value:T):T{
    return value;
}
getData2<string>("小牛");


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
装饰器
装饰器是一种特殊类型的声明,它能够被附加到类,方法属性或参数上,可以修改类的行为,通俗的讲装饰器就是一个方法,可以注入到类,方法,性或参数上来扩展类、方法属性或参数的功能。常见的装饰器有:类装饰器,方法装饰器,属性装饰器,参数装饰器。
装饰器的写法:普通装饰器(无法传参),装饰器工厂(可传参),装饰器是过去几年中JS最大的成就之一,已是ES7的标准特性之一

类装饰器
类装饰器:普通装饰器(无法传参)

// 类装饰器 : 普通装饰器 (不能传参)

function logClass(params:any){ 
    console.log(params); // params 代表当前类
    params.prototype.name = "普通装饰器的属性";
    params.prototype.run = function(){
        console.log("普通装饰器原型动态添加方法")
    }
}

@logClass
class HttpClient{
}
const http:any = new HttpClient();
console.log(http.name);
http.run();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
装饰器:工厂装饰器(可传参)

// 类装饰器:工厂装饰器(可以传参)
function logClass(param:string){
    return function(target:any){
        console.log(target) // target 当前类
        console.log(param) // param 当前类传进来的参数
        target.prototype.url = param;
    }
}
@logClass("http:www.xiaoniuniu.com")
class HttpClient{

}
var httpClient:any = new HttpClient();
console.log(httpClient.url); 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
属性装饰器
属性装饰器会被应用到属性描述上,可以用来监视,修改或替换属性内容

属性装饰器会在运行时传入两个参数

​ 1.对于静态成员来说是类的构造函数,对于实例来说是类的原型对象

​ 2.成员的名字

// 属性装饰器
function logProperty(params:any){ // params就是当前类传递进来的参数
    return function(target:any,attr:any){
        console.log(target)
        console.log(params)
        target[attr] = params;
    }
}

class HttpClient{
    @logProperty("http:www.niuxiaoniu.com")
    public url :any | undefined;

    getData(){
        console.log(this.url);
    }
}
var http = new HttpClient()
console.log(http.url)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
方法装饰器
方法装饰器会被应用到方法描述上,可以用来监视、修改或者替换方法定义

方法装饰器会在运行时传入下列3个参数

1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象

2.成员的名字

3.成员的属性描述符

function get(param:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target)
        console.log(methodName)
        console.log(desc)
        target.urlAPI = param;
        target.run = function(){
            console.log("方法装饰器")
        }
    }
}

class HttpClient{
    url : any | undefined;
    constructor(){

    }
    @get("http://www.niuxiaoniu.com")
    getData(){
        console.log(this.url)
    }
}
const http:any = new HttpClient();
console.log(http.urlAPI)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
方法参数装饰器
参数装饰器表达式会在运行时当作函数调用,可以使用参数装饰器为类的原型增加一些元素数据 ,传入下列3个参数:

1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

2.方法的名字。

3.参数在函数参数列表中的索引。

function logParam(param:any){
    return function(target:any,paramIndex:any){
        console.log(target)
        console.log(methodName)
        console.log(paramIndex)
        target.urlAPI = param;
    }
}
class HttpClient{
    getData(@logParam("123456") uuid:any){
        console.log(uuid);
    }
}
const http:any = new HttpClient();
http.getData(123456);
console.log(http.urlAPI)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
装饰器执行顺序
装饰器执行顺序 : 属性装饰器 ————> 方法装饰器 ————> 方法参数装饰器 ————> 类装饰器

模块化
模块化是将一个大的程序,拆分成多个小文件,然后将小文件组合起来

模块化优点:

防止命名冲突
代码复用性
高维护性
模块化主要由 import 和 export 构成

export 模块对外暴露
import 引入暴露的模块
export
单个暴露

// 单独暴露 在需要暴露的内容前面加入 export关键字
export let school = "我爱学习";

export function getData(){
    console.log("我可以改变你")
}

1
2
3
4
5
6
7
统一暴露

let msg = "嘿嘿";
function getMsg(){
    console.log("哈哈")
}
export {msg,getMsg};

1
2
3
4
5
6
认暴露

// 认暴露 以对象形式暴露
export default{
    name:"Hello",
    show(){
        console.log("Hello Show");
    }
}

1
2
3
4
5
6
7
8
Import
认引入

// 引入 将暴露的内容全部引入 并赋值给m1
import * as m1 from "./export";

1
2
3
解构赋值引入

// 解构赋值形式引入
import {msg,getMsg} from "./export2";

1
2
3
针对于认暴露引入

import m2 from "./export3";

1
2
命名空间
命名空间:在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能函数、类、接口等放置到命名空间内,同Java的包,TypeScript的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象,命名空间内的对象通过export关键字对外暴露

命名空间和模块的区别:

命名空间:内部模块,主要用于组织代码,避免命名冲突。
模块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间
namespace A{
    interface Animal {
        name: string;
        eat(): void;
    }
    export class Dog implements Animal {
        name: string;
        constructor(name: string) {
            this.name = name;
        }
        eat(): void {
            console.log(`${this.name} ---- 吃骨头!!!`);
        }
    }
    export class Cat implements Animal {
        name: string;
        constructor(name: string) {
            this.name = name;
        }
        eat(): void {
            console.log(`${this.name} ----吃猫粮!!!`);
        }
    }
}
const aDog = new A.Dog("小狗狗");
aDog.eat();

const aCat = new A.Cat("小喵喵");
aCat.eat();


————————————————
原文链接:https://blog.csdn.net/weixin_45764643/article/details/116465126

装饰器:https://ninghao.net/blog/7384

相关文章

原文连接:https://www.cnblogs.com/dupd/p/5951311.htmlES6...
以为Es6,javascript第一次支持了module。ES6的模块化分为导...
视频讲解关于异步处理,ES5的回调使我们陷入地狱,ES6的Prom...
TypeScript什么是TypeScript?TypeScript是由微软开发的一款开...
export class AppComponent { title = 'Tour of heroes...
用 async/await 来处理异步昨天看了一篇vue的教程,作者用as...