Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记

文章目录

    • 启动自动监视,编译代码
    • ts中的类型编写
    • ts中的类,接口等相关内容
      • es5中类,继承相关内容
      • ts的类,接口相关内容
    • ts泛型(泛型定义,泛型函数,泛型类,泛型接口)
    • 通过ts泛型模拟不同数据库使用
    • ts结构之命名空间,模块
      • 初识命名空间概念以及namespace,export关键字
      • 命名空间模块化
    • ts之装饰器
      • 开启ES7标准
      • 属性装饰器
      • 方法装饰器
      • 方法参数装饰器
      • 装饰器执行顺序

启动自动监视,编译代码

在D盘创建一个tsProject目录作为Typescript学习目录。
在vscode打开该文件夹,使用命令行输入:tsc --init
初始化文件夹后,会生成自动tsconfig.json,默认是没有这个文件的。
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第1张图片

新键一个index.ts,打开注释修改自动编译路径,"outDir":"./js"
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第2张图片
编写ts文件,写入let str:string="hello ts" 然后保存
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第3张图片
在终端处选择运行任务,然后选typescript,然后选择监视
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第4张图片
它就会监视文件,自动编译文件到指定目录输出,我们在index.ts加一行代码保存验证一下
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第5张图片

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第6张图片
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第7张图片
老版本的路径有点不一样,我们也可以直接使用我们控制台输出的那个命令,一样的效果,监视的前提是必须已经初始化了。

监视指令为:tsc -p 路径\tsconfig.json --watch
如和本文一致路径可直接使用以下指令开启
tsc -p d:\tsProject\tsconfig.json --watch

接下来现在文件夹创建一个index.html
然后引入我们js目录下的js文件


<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>indextitle>
        
    head>
    <body>
        <div id="box">
            box
        div>
    body>
html>
<script src="js/index.js">script>

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第8张图片

ts中的类型编写

接下来就是熟悉ts中各种类型的编写:(继续在我们的index.ts文件中编写内容)

let str: string = "hello,ts"

let str1: string = "hello,typescript"

//布尔类型(boolean) true false
var flag: boolean = true

//数字类型(number)
var a: number = 123
console.log(a)
//a="123"  错误写法,因为已经指定类型
a = 1.23  //不报错,Number类型包括整型和浮点型
console.log(a)
//数组类型(array)   ts中定义数组有两种方式
//es5中,写法,什么类型都可以放在一个数组中
//var array=[12,true,"js"]
//1.ts中,第一种定义数组的方法
let arr1: string[] = ["java", "c#"]
console.log(arr1)

//2.ts中,第二种定义数组的方法
//如果要写字符串就是把的number换成string就可以
let arr2: Array<number> = [1, 12, 12.3]
console.log(arr2)

//3.ts中,第三种定义数组的方法(any放任意类型)
let arr3: any[] = ["str", 12, false, arr1]
console.log(arr3)

//元组类型(tuple)     属于数组的一种
//等式两边的类型必须一致
let arr: [string, number, boolean] = ["ts", 3.14, false]
console.log(arr)

//枚举类型(enum)
/*
    enum  枚举名{
        标识符[=整数常量]
        标识符[=整数常量]
        标识符[=整数常量]
        ...
        标识符[=整数常量]
    };

    常用场景   pay_status   0  未支付  1  支付   2交易成功
              flag    1表示true   0表示false

*/

enum Flag { success = 1, error = 0 }
var f: Flag = Flag.success
console.log(f)

enum color { red = 1, green = 2, blue = 3 }

enum Err { 'undefined' = -1, 'null' = -2, 'success' = 1 }
var e: Err = 1
console.log(e)

//任意类型(any)
let num: any = 12
num = "str"
num = true
num = [123, 12]

//任意类型的用处,可以不出现警告
var oBox: any = document.getElementById('box');

oBox.style.color = 'red';

//null和undefined  其他(never类型)数据类型的子类型
/*
    var variable:number;   //没初始化赋值

    console.log(variable);  //报错


    var variable:undefined;

    console.log(variable); //不报错,输出:undefined,是正确的

    var variable:null;
    variable=null;

*/
//类型为未定义或者是数字类型或者null类型
var variable: number | undefined | null;

console.log(variable)

//void类型,主要用于定义方法,如果方法没有返回值就使用冒号void
function run(): void {
    console.log('run')
}//即为方法没有返回任何类型

run();

//never类型,重来不会出现的类型

// var b:never;
// b=(()=>{

//     throw new Error('错误');
// })()//先注释了,不然下面的代码使用函数调用有问题

//3.1  函数定义
//es5定义函数的方法        
//函数声明法
function fun() {
    return 'fun';
}

var fun1 = function () {
    return 'fun';
}

//ts中定义函数

//函数声明法
function fun2(): string {
    return 'fun';
}

/* 
    function fun2():string{
        return '123';
    }//错误写法,函数类型和返回值类型必须一致
*/

//匿名函数

var fun3 = function (): number {
    return 123;
}

alert(fun3());//调用方法

//ts中定义方法传参
//返回值使用飘符号$括号属性飘符号取值
//看代码颜色可区分,注意和单引号区分
function getinfo(name: string, age: number): string {
    return `${name} --- ${age}`;
}
//传参也必须是和函数方法参数类型一致,不一致会有编译问题
alert(getinfo('zhangsan', 20));

//匿名函数
var getinfo1 = function (name: string, age: number): string {
    return `${name} --- ${age}`;
}
alert(getinfo1('lisi', 19));

//没有返回值的方法
function noreturn(): void { }
noreturn();

//3.2方法可选参数

//es5里面方法的实参和形参可以不一样,但是ts必须一致
//如果不一样需要配置可选参数
function getinfo2(name: string, age?: number, sex?: string): string {
    if (age) {
        return `${name} --- ${age}`;
    } else {
        return `${name} ---年龄保密`;
    }
}
alert(getinfo2('wangwu'));
//可选参数以参数?:类型的形式存在,而且必须在参数的末尾配置,可配置多个可选参数

//3.3默认参数   类似可选参数
//es5里面没法设置参数,es6和ts中都可以设置默认参数
function getInfo(name: string, age = 25): string {
    if (age) {
        return `${name} --- ${age}`;
    } else {
        return `${name} ---年龄保密`
    }
}
//没有传参,默认就会有25出现
alert(getInfo('张三'));

//3.4剩余参数
/*
    function sum(a:number,b:number,c:number){
     return a+b+c;   
    }
*/

//三点运算符   接收形参传过来的值
function sum(...result: number[]): number {

    var sum = 0;

    for (var i = 0; i < result.length; i++) {
        sum += result[i];
    }
    return sum;
}

alert(sum(1, 2, 3));

//3.5 ts函数的重载
//java中方法的重载,重载是指的是两个或者两个以上的同名函数,但它们的参数不一样,这时会出现函数重载的情况
//typescript中的重载,通过为统一函数提供多个函数类型定义来试下多种功能的目的
//ts为了兼容es5以及es6重载的写法和java中有区别

//es5中出现同名方法,下面的会替换上面的方法
/*
    function css(config){}
    function css(config,value){}    
 
 */


//ts中的重载
function getReload(name: string): string;

function getReload(age: number): number;

function getReload(str: any): any {
    if (typeof str === 'string') {
        return '我叫: ' + str;
    } else {
        return '我的年龄是' + str;
    }
}

alert(getReload('李四'));//传的必须要已经声明了的方法,如这个不能传boolea,因为没有声明
//alert(getReload(true));//在此处算错误写法
function getReload1(name: string): string;
function getReload1(name: string, age: number): string;

function getReload1(name: any, age?: any): string {
    if (age) {
        return '我叫: ' + name + '我的年龄是' + age;
    } else {
        return '我叫: ' + name;
    }
}

alert(getReload1('王五', 15));
alert(getReload1('王五'));
//alert(getReload1('王五',true))//错误,由于未定义有boolean类型的形参

//3.6 箭头函数  es6
//箭头函数中,this指向上下文

// setTimeout(function(){

//     alert('timeout')
// },1000)//es5的写法

setTimeout(() => {
    alert('timeout')
}, 1000)


ts中的类,接口等相关内容

es5中类,继承相关内容

1.先创建一个html,可利用vscode快速生成模板
步骤:创建一个名为es5创建对象 继承html后缀文件,创建后在文本内容里输入:/ 然后按下Tab键即可。
可参考我另外一篇博客:https://blog.csdn.net/xtho62/article/details/108883298
然后就是相关联系的代码啦!亮代码啦


<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    
body>
<script>
    //es5里面的类

//1.最简单的类,以前没class,所有类在以前是使用function关键字来修饰,从而达到效果
    // function Person(){
    //     this.name='张三';
    //     this.age=20
    // }
    // var p=new Person();
    // alert(p.name);

//2.构造函数和原型链里面增加方法
    /*
        function Person(){
            this.name='张三';//属性
            this.age=20;

            this.run=function(){//实例方法
                
                alert(this.name+'在运动')
            }
        }
    
        Person.getInfo=function(){
            alert('我是静态方法');
        }

        //原型链上面的属性会被多个是咯共享    构造函数不会
        Person.prototype.sex='男';
        Person.prototype.work=function(){ 
            alert(this.name+'在工作')
        }

        var p=new Person();
        //alert(p.name);
         
        p.run();
        p.work();

        Person.getInfo();
    */

//4.es5里面的继承
         
        // function Person(){
        //     this.name='张三';//属性
        //     this.age=20;

        //     this.run=function(){//实例方法
                
        //         alert(this.name+'在运动')
        //     }
        // }
    
        // Person.getInfo=function(){
        //     alert('我是静态方法');
        // }

        // //原型链上面的属性会被多个是咯共享    构造函数不会
        // Person.prototype.sex='男';
        // Person.prototype.work=function(){ 
        //     alert(this.name+'在工作')
        // }

        // var p=new Person();
        // //alert(p.name);
         
        // p.run();
        // p.work();

        // Person.getInfo();

        // //Web类 继承Person类    原型链对象冒充的组合继承模式
        // function Web(){
        //     Person.call(this);//对象冒充实现继承            
        // }

        // var w=new Web();
        // //w.run();  //对象冒充可以继承构造函数里面的属性和方法

        // //报错
        // w.work();//对象冒充可以继承构造函数里面的属性和方法   单没法继承原型连上面的属性和方法
        
//5.web类 继承Person类  原型链+对象冒充的组合继承模式
// function Person(){
//             this.name='张三';//属性
//             this.age=20;

//             this.run=function(){//实例方法
                
//                 alert(this.name+'在运动')
//             }
//         }

//         //原型链上面的属性会被多个是咯共享    构造函数不会
//         Person.prototype.sex='男';
//         Person.prototype.work=function(){ 
//             alert(this.name+'在工作')
//         }

//         //Web类 继承Person类  原型链+对象冒充的组合继承模式
         
//         function Web(){

//         }
//         Web.prototype=new Person(); //原型链实现基础 
        
//         var w=new Web();

//         w.run();
//         w.work();
//         //原型链继承既可以继承原型链上的方法,也可以继承构造函数上的方法

//6.原型链实现继承的   问题?
    // function Person(name,age){
    //     this.name=name;//属性
    //     this.age=age;
    //     this.run=function(){//实例方法
    //         alert(this.name+'在运动');
    //     }
    // }
    // Person.prototype.sex='男';
    // Person.prototype.work=function(){
    //     alert(this.name+'在工作');
    // }

    // //var p=new Person('李四',20);
    // //p.run();
    // function Web(name,age){
        
    // }
    // //使用Web继承
    // Web.prototype=new Person();

    // var w=new Web('赵四',20);//实例化字类的时候没法给父类传参

    // w.run();//调用run方法不是赵四在运动而是undefined在运动


//7.原型链+构造函数的组合继承模式
 
    function Person(name,age){
        this.name=name;//属性
        this.age=age;
        this.run=function(){//实例方法
            alert(this.name+'在运动');
        }
    }
    Person.prototype.sex='男';
    Person.prototype.work=function(){
        alert(this.name+'在工作');
    }

    //var p=new Person('李四',20);
    //p.run();
    function Web(name,age){
        Person.call(this,name,age)
    }
    //使用Web继承
    Web.prototype=Person.prototype;

    var w=new Web('王五',20);//实例化字类的时候没法给父类传参
    w.work();
    w.run(); 
script>
html>

这里总结一句就是冒充对象实际上就是利用改变this的指向来完成继承

ts的类,接口相关内容

//1.ts中类的定义
/*
  es5中:
    function Person(name){
        this.name=name
        this.run=function(){
            console.log(this.name)
        }
    }
    var p=new Person('张三');
    p.run();
*/

//ts写法
// class Person{
//     name:string ; //属性   前面省略了public关键词

//     constructor(n:string){ //构造函数   实例化类的时候触发的方法 
//         this.name=n;
//     }

//     run():void{
//         alert(this.name)
//     }
// }
// var p=new Person('张三');
// p.run()


// class Person {
//     name: string; //属性   前面省略了public关键词

//     constructor(n: string) { //构造函数   实例化类的时候触发的方法 
//         this.name = n;
//     }

//     run(): void {
//         alert(this.name)
//     }
// }
// var p = new Person('张三');
// p.run()

/*
class Person{
    name:string;

    constructor(name:string){
        this.name=name
    }

    getName():string{
        return this.name;
    }

    setName(name:string):void{
        this.name=name
    }
}
var p=new Person('法外狂徒');
alert(p.getName());

p.setName('张三');
alert(p.getName());
*/

//2.ts中实现继承   extends,super
// class Person {
//     name:string;//没写表示共有
//     constructor(name:string) {
//         this.name=name;
//     }
//     run():string{
//         return `${this.name}在运动`;
//     }
// }

// //var p=new Person('马六');
// //alert(p.run());

// //展示继承和多态
// class Web extends Person{
//     constructor(name:string){
//         super(name);
//     }
//     run():string{
//         return `${this.name}在运动,走的子类方法`;
//     }

//     work():string{
//         return `${this.name}  在工作`;
//     }
// }

// var w=new Web('小七');
// alert(w.run()); 
// alert(w.work());


//3  类里面的修饰符  ts中定义属性的时候给我们提供了   三种修饰符
/*
    public :共有            在类里面,子类,类外都可以访问
    protected:保护类型      在类里面,子类里面可以访问,在类外部没法访问
    private:私有            在类里面可以访问,字类。类外部都没法访问

    属性不加修饰符,默认为public
*/
  
 //共有public
    // class Person {
    //     name:string;//没写表示共有
    //     constructor(name:string) {
    //         this.name=name;
    //     }
    //     run():string{
    //         return `${this.name}在运动`;
    //     }
    // }
    //  var p=new Person('hehe');
    //  alert(p.name);//打印出hehe

//保护protected
class Person {
    protected name:string; 
    constructor(name:string) {
        this.name=name;
    }
    run():string{
        return `${this.name}在运动`;
    }
}

class Web extends Person{
    
    constructor(name:string){
        super(name);
    }
    work(){
        alert(`${this.name}在工作`);
    }
}
var w=new Web('小四');
//var p=new Person('小五');
//p.name   //报错在protected无法访问,这是外部直接调用的写法
w.work();
alert(w.run());

//private :私有   它类里面可以访问,字类,类外部都没法访问
//name被Private修饰,子类调用${this.name}无法编译通过
//调用自己则可以
class Person1 {
    private name:string; 
    constructor(name:string) {
        this.name=name;
    }
    run():string{
        return `${this.name}在运动`;
    }
}
var p1=new Person1('p1');
alert(p1.run());//打印p1在运动

 //4.静态属性   静态方法
    //es5里面调用静态写法
    // function Person(){
    //     this.run1=function(){}
    // }

    // Person.name='嘻嘻';  
    // Person.run2=function(){//静态方法

    // }
    // var p=new Person();
    // Person.run2();//静态调用

    //静态调用在jq里挺多应用的,有兴趣可以去了解一下

    class Per{
        public name:string
        static sex:string='女';
        constructor(name:string){
            this.name=name;
        }

        run(){   //实例方法
            alert(`${this.name}在运动`);
        }
        work(){
            alert(`${this.name}在工作`);
        }

        static print(){  //静态方法,静态只能调用静态 
            alert('print方法'+Per.sex);
        }
    }
    Per.print();
    alert(Per.sex);

    //多态:父类定义一个方法不去实现,让继承它的子类去实现,每一个子类都有不同的表现

    //多态属于继承

    // class Animal{
    //     name:string;
    //     constructor(name:string){
    //         this.name=name;
    //     }
    //     eat(){
    //         console.log('吃的方法');
    //     }
    // }

    // class Dog extends Animal{
    //     constructor(name:string){
    //         super(name);
    //     }

    //     eat(){
    //         return this.name+'吃粮食'
    //     }
    // }
 
    // class Cat extends Animal{
    //     constructor(name:string){
    //         super(name);
    //     }
    //     eat(){
    //         return this.name+'吃老鼠'
    //     }
    // }
    // //var dog=new Dog('狗');
    // var cat=new Cat('猫');
    // alert(cat.eat());

    //typescript中的抽象类,它是提供其他类继承的基类,不能被直接实现
    //abstract关键字定义抽象类和抽象方法
    //抽象类中的抽象方法不包含具体实现实现必须在派生类中实现,不能直接new
    // abstract class Animal {
    //     name:string;
    //     constructor(name:string) {
    //         this.name=name
    //     }
    //     abstract eat():any;
    // }

    // class Dog extends Animal{
         
    //     constructor(name:string){
    //         super(name);
    //     }
    //     eat() {
    //         //throw new Error("Method not implemented.")
    //         console.log(this.name+'吃粮食');
    //     }
         
    // }
    // var d=new Dog('旺财');
    // d.eat();

    // abstract class Bird extends Animal{
    //     constructor(name:string){
    //         super(name)
    //     }
    //     abstract eat():any;
    // }

//接口=》定义标准规范限制,灵活,扩展性更高
/*
    属性类型接口
    函数类型接口
    可索引类型接口
    类类型接口
    接口扩展
*/ 
    //1.属性接口   对json的结果
    //ts中定义方法
    // function printLabel():void{
    //     console.log('printLabel');
    // }
    // printLabel();

    //ts中定义方法传入参数
    // function printLabel(label:string):void{
    //     console.log('printLabel');
    // }
    // //printLabel(123);//错误写法
    // printLabel('456');

    //ts中自定义方法参入参数对json进行约束
    // function printLabel(labelInfo:{label:string}):void{
    //     console.log('printLable');
    // }
    // //printLabel('haha');//错误写法
    // //printLabel({name:'zhangsan'}) //错误写法
    // printLabel({label:'zhangsan'});

    //对批量方法传入参数进行约束

    //传入对象的约束      属性接口
    interface FullName{
        firstName:string;  //注意分号结束
        secondName:string;
    }

    function printName(name:FullName){
        //必须传入对象  firstName,secondName
        console.log(name.firstName+'--'+name.secondName);
    }

    var obj={
        age:15,
        firstName:'wang',
        secondName:'wu'
    }
    printName(obj);

    function printInfo(info:FullName){
        //必须传入对象 firstName,secondName 
        console.log(info.firstName+'--'+info.secondName);
    }

    printInfo({
        firstName:'xiao',
        secondName:'liu'
    })

//接口,可选属性,一行是在属性后面冒号前面加问号
interface AllName{
    firstName:string;  //注意分号结束
    secondName?:string; 
}
function getName(name:AllName){
    console.log(name);
}
getName({
    firstName:'仨'
}) 

//以属性类型接口,封装ajax写法
interface Config{
    type:string;
    url:string;
    data?:string
    dataType:string
}
//原生js封装的ajax,不兼容ie6
// function ajax(config:Config){
//     var xhr=new XMLHttpRequest();

//     xhr.open(config.type,config.url,true);
//     xhr.send(config.data);
//     xhr.onreadystatechange=function(){

//         if (xhr.readyState==4 && xhr.status==200) {
//             console.log('chenggong');
//             if (config.dataType=='json') {
//                 console.log(JSON.parse(xhr.responseText));
//             } else {
//                 console.log(xhr.responseText)
//             }
            
//         }
//     }
// }

// ajax({
//     type:'get',
//     url:'http://www.baidu.com',
//     dataType:'json'
// })

//函数类型接口:对方法传入的参数  以及返回值进行约束   可以做批量约束
//实现加密类型的函数接口
interface encrypt{
    (key:string,value:string):string
}

var md5:encrypt=function(key:string,value:string):string{
    //省略md5算法代码
    //模拟操作
    return key+value;
}

console.log(md5('name','zhangsan'));


var sha1:encrypt=function(key:string,value:string):string{
    //省略sha1算法代码
    //模拟操作
    return key+'---'+value;
}
console.log(sha1('name','lisi'));

//可索引接口,数组,对象的约束 (不常用)


//ts定义数组的方式
    // var array:number[]=[123,456];
    // var array1:Array=['12','34'];

    //对数组的约束  即可索引约束
    // interface UserArr{
    //     [index:number]:string
    // }

    // var array:UserArr=['123','3245'];
    // console.log(array[0]);

    //对对象约束   不常用
    // interface UserObj{
    //     [index:string]:string
    // }

    // var arrObj:UserObj={name:'zhangsan'};

//类类型接口:对类的约束  和抽象类有点相似   
    // interface Animal{
    //     name:string

    //     eat(str:string):void;
    // }

    // class Dog implements Animal{
    //     name:string
    //     constructor(name:string){
    //         this.name=name;
    //     }
    //     eat(){
    //        console.log(this.name+'吃粮食');
    //     }
    // }
    // var d=new Dog('小黑');
    // d.eat();

    // class Cat implements Animal{
    //     name:string;
    //     constructor(name:string){
    //         this.name=name;
    //     }
    //     eat(food:string){
    //         console.log(this.name+food)
    //     }
    // }

    // var c=new Cat('小花');
    // c.eat('老吃鼠');

//接口扩展,接口可以继承接口
    // interface Animal{
    //     eat():void;
    // }
    // interface Person2 extends Animal{
    //     work():void;
    // }
    // class Web2 implements Person2{
    //     name:string
    //     constructor(name:string){
    //         this.name=name;
    //     }

    //     eat(){
    //         console.log(this.name+'喜欢吃饭')
    //     }
    //     work(){
    //         console.log(this.name+'的工作是敲代码')
    //     }
    // }

    // var web2=new Web2('xiaolei');
    // web2.work();

    interface Animal{
        eat():void;
    }
    interface Person2 extends Animal{
        work():void;
    }

    class Programmer{
        name:string;
        constructor(name:string){
            this.name=name;
        }
        coding(code:string){
            console.log(this.name+code);
        }
    }

    class Web2 extends Programmer implements Person2{
        public name:string
        constructor(name:string){
            super(name);
            this.name=name;
        }
    
        eat(){
            console.log(this.name+'喜欢吃饭')
        }
        work(){
            console.log(this.name+'的工作是敲代码')
        }
    }

    var web2=new Web2('xiaolei');
    web2.work();
    web2.coding('在写ts代码');

ts泛型(泛型定义,泛型函数,泛型类,泛型接口)

/*
    泛型就是解决 类 接口 方法的复用性  以及对不特定数据类型的支持
*/
// function getData(value:string):string{
//     return value;
// }

//T表示泛型,具体什么类型是调用这个方法的时候决定的
// function getData(value:T):T{
//     return value;
// }
// getData(123);
// getData('1231');
// getData(true);
// //getData('123');//错误写法

//泛型类,比如有一个最小堆算法,需要同时支持返回数字和字符串两种类型。  通过类的泛型来实现

// class MinClass{
//     public list:number[]=[];

//     add(num:number){
//         this.list.push(num);
//     }

//     min():number{
//         var minNum=this.list[0];

//         for(var i=0;i
//             if(minNum>this.list[i]){
//                 minNum=this.list[i];
//             }
//         }
//         return minNum;
//     }
// }

// var m=new MinClass();
// m.add(3);
// m.add(2);
// m.add(15);

//上面是只返回数字,下面演示泛型改良版,同时支持数字和字符串,根据传参返回
//类的泛型
class MinClass<T>{
    public list:T[]=[];
    
    add(value:T):void{
        this.list.push(value)
    }
    min():T{
        var minNum=this.list[0];
        for(var i=0;i<this.list.length;i++){
            if(minNum>this.list[i]){
                minNum=this.list[i];
            }
        }
        return minNum;
    }       
}

var m1=new MinClass<number>();//实例化类,并且指定了类的代表的类型是number
m1.add(3);
m1.add(2);
m1.add(15);

alert(m1.min());

var m2=new MinClass<string>();//实例字符串,根据Asic码(忘记是不是这样打了哈哈)
m2.add('a');
m2.add('s');
m2.add('das');
alert(m2.min());

//ts中的泛型
    // 泛型的定义
    // 泛型函数
    // 泛型类
    // 泛型接口

    //函数型接口
    // interface ConfigFn{
    //     (value1:string,value2:string):string;
    // }

    // var setData:ConfigFn=function(value1:string,value2:string):string{
    //     return value1+value2;
    // }

    // setData('name','zhangsan');

    //泛型接口   第一种
    // interface ConfigFn{
    //     (value:T):T;
    // }

    // var getData:ConfigFn=function(value:T):T{
    //     return value;
    // }

    // getData('zhangsan');
    // getData(false);

    //泛型接口  第二种
    interface ConfigFn<T>{
        <T>(value:T):T;
    }

    function getData<T>(value:T):T{
        return value;
    }

    var myGetData:ConfigFn<string>=getData;
    myGetData('123');
/**
  * 定义一个User的类这个类的作用就是映射数据库字段
  * 然后定义一个MysqlDb的这个类用于操作数据库
  * 然后把User类作为参数传入MysqlDb中
  */

//   class ArticleCate{
//       title:string|undefined;
//       desc:string|undefined;
//       status:number|undefined;
//   }

//   class User{
//       username:string|undefined;
//       password:string|undefined;
//   }

//   class MysqlDb{
//       add(info:ArticleCate):boolean{//校验用户则使用user:User
//           console.log(info);
//           return true;
//       }
//   }
// //   var u=new User();
// //   u.username='zhangsan';
// //   u.password='123456';
// //   var Db=new MysqlDb();
// //   Db.add(u);

// var art=new ArticleCate();
// art.status=1
// art.desc='国内新闻'
// art.title='国内'

// var Db=new MysqlDb();
// Db.add(art);


//操作数据库的泛型类
class MysqlDb<T>{
    add(info:T):boolean{
        console.log(info);
        return true;
    }
    update(info:T,id:number):boolean{
        console.log(info);
        console.log(id);
        return true;
    }
}

//想给User表增加数据
//1.定义一个User类和数据库进行映射
class User{
   username:string | undefined;
   password:string | undefined;
}

var u=new User();
u.username='张三';
u.password='123456';
var Db=new MysqlDb<User>();
Db.add(u);

//2.定义文章分类的类
class ArticleCate{
      title:string | undefined;
      desc:string | undefined;
      status:number | undefined;
      constructor(params:{
            title:string | undefined,
            desc:string | undefined,
            status?:number | undefined
        }){
            this.title=params.title;
            this.desc=params.desc;
            this.status=params.status;
      }
}
var art=new ArticleCate({
    title:'分类11',
    desc:'123',
    status:1
});//打印的时候出现undefined注意检查构造函数右边是不是params.
art.status=0;
//把类当作参数的泛型类
var myDb=new MysqlDb<ArticleCate>();
myDb.update(art,12);

通过ts泛型模拟不同数据库使用

/**
 * 定义一个操作数据库的库   支持Mysql   Mssql   MongoDb
 * 
 * 要求1:Mysql   Mssql   MongoDb功能一样  都有 add update delete get方法
 *      注意:约束统一的规范,以及代码重构
 *      
 *      解决方案:需要约束规范所以要定义接口,需要代码重用所以使用泛型
 *      1.接口:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范
 *      2.泛型  通俗理解:泛型就是解决  类  接口  方法的复用性
 * 
 */ 

interface DBI<T>{
    add(info:T):boolean;

    update(id:number):boolean;

    get(id:number):any[];
}

//定义一个操作mysql数据库的类
class MySqlDb<T> implements DBI<T>{
    add(info: T): boolean {
        console.log('mysql数据库连接成功');
        return true;
    }
    update(id: number): boolean {
        throw new Error("Method not implemented.");
    }
    get(id: number): any[] {
        throw new Error("Method not implemented.");
    }
     
}

//定义一个操作mssql数据库的类
class MsSqlDb<T> implements DBI<T>{
    add(info: T): boolean {
        console.log('mssql数据库连接成功');
        return true;
    }
    update(id: number): boolean {
        throw new Error("Method not implemented.")
    }
    get(id: number): any[] {
        
        var list=[
            {
                title:'xxx',
                desc:'xxxxx'
            },
            {
                title:'xx1',
                desc:'xxxx1'
            }
        ]

        return list;
    }
}

//操作用户表  定义一个User类和数据表映射
class User{
    username:string | undefined
    password:string | undefined
}

var u=new User();
u.password='123';
u.username='lisi';

var oMySql=new MySqlDb<User>();
oMySql.add(u);

var oMssql=new MsSqlDb<User>();
oMssql.add(u);

var data=oMssql.get(4);
console.log(data);

ts结构之命名空间,模块

概念:

  • 命名空间:

    • 在代码量比较打的情况下,为了避免各种变量命名相冲突,可将相似功能的函数,类,接口等防止到命名空间内同java的包,.net的命名空间一样,ts的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。
  • 命名空间和模块的区别:
    命名空间:内部模块,主要用于组织代码,避免命名冲突
    模块:ts的外部模块的简称,侧重代码的复用,一个模块可能会有多个模块

初识命名空间概念以及namespace,export关键字

先认识一些关键词:namespace命名空间类似于java的包,namespace A{代码},namespace B{代码},这样即使代码一模一样也不影响,因为A和B是完全互相不干扰的空间,在此空间下所有的代码都是私有的,在空间外实例需要A.(A点),但是实例类需要实例的类前面有被关键字export(导出)修饰。


看看下列示例:

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第9张图片

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第10张图片

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第11张图片
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第12张图片
说明export关键字的类,是通过无法调用命名空间点类来实例,我们修改一下,让B的Dog也被修饰。

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第13张图片

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第14张图片

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第15张图片
证明此结论,其作用就是用于区分,组织代码,避免命名冲突

命名空间模块化

首先在根目录下,创建modules模块目录,将A,B命名空间放在这个modules下的a.ts中,并且使用export命名空间导出命名空间A,B暴露出来,再在index.ts中导入我们要的模块的ts文件,详细请看下图
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第16张图片
然后使用cmd打开js目录,使用node index.js进行渲染,才能看见效果,因为浏览器看不出模块export暴露效果。
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第17张图片
出现了错误:ReferenceError: document is not defined,此前的代码有一些可能对渲染有影响,先将之前代码剪切到一个新的ts文件下,index.js下只剩当前需要测试的代码。
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第18张图片
再重新测试:
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第19张图片
证明成功
测试导多个命名空间:
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第20张图片
index.ts下的代码

/*
命名空间:
    在代码量比较打的情况下,为了避免各种变量命名相冲突,可将相似功能的函数,类,接口等防止到命名空间内
    同java的包,.net的命名空间一样,ts的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。

    命名空间和模块的区别:
        命名空间:内部模块,主要用于组织代码,避免命名冲突
        模块:ts的外部模块的简称,侧重代码的复用,一个模块可能会有多个模块

*/
import {A,B} from './modules/a';
var d=new A.Dog('小黑');
d.eat();
var dog=new A.Dog('小白');
dog.eat();

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第21张图片

ts之装饰器

装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或者参数上,可以修改类的行为

通俗的讲修饰器就是一个方法,可以注入到类,方法,属性参数上
来扩展类,属性,方法,参数的功能

  • 常见的装饰器:类装饰器,属性装饰器,方法装饰器,参数装饰器

  • 装饰器的写法:普通装饰器(无法传参),装饰器工厂(可传参)

  • 装饰器是过去几年中js最大的成就之一,已经是ES7的标准特性之一

开启ES7标准

先注释了模块导入的代码,再开始编写修饰器相关代码,当然要先配置打开es7检查。那怎么打开呢,一个是全局打开,一个是在项目的tsconfig处打开,不然会出现编译报错的情况,能运行但是看着很难受!
注释打开"experimentalDecorators": true,

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第22张图片
不打开的话:
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第23张图片
打开就不报错
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第24张图片
关于去波浪线的解决方案,更详细得请看我另外一篇文章:
https://blog.csdn.net/xtho62/article/details/108919689

接下来先介绍 类装饰器
1.类装饰器:类装饰器在类声明之前被声明(紧靠着声明),类装饰器应用于类构造函数,可以用来监视,修改或替换定义。
先看看普通类装饰器

//类装饰器   //普通装饰器
function logClass(params:any){
    console.log(params);
    //params就是当前类
    params.prototype.apiUrl='动态扩展的属性';
    params.prototype.run=function(){

        console.log('我是一个run方法');
    }
}

@logClass
class HttpClient{
    constructor(){

    }
    getData(){

    }
}
var http:any=new HttpClient();
console.log(http.apiUrl);       
http.run();

可以扩展原有代码的功能属性,如下图看结果可知
Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第25张图片
普通修饰器无法传参构造增强,其增强更多依赖于prototype原型

当然传参这一块也是有解决方案的,来看看修饰工厂:

//1.2 类装饰器:装饰工厂(可传参)
function logClass(params:string){

    return function(target:any){//注意要写any,target表示当前要装饰的目标
        console.log(target);
        console.log(params);
    }
}

@logClass('hello')
class HttpClient{
    constructor(){

    }
    getData(){

    }

}

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第26张图片

function logClass(params:string){//这里的params为传参的值

    return function(target:any){//注意要写any,target表示当前要装饰的目标
        console.log(target);
        console.log(params);

        target.prototype.apiUrl=params;
    }
}

@logClass('http://www.baidu.com')
class HttpClient{
    constructor(){

    }
    getData(){

    }

}

var http:any=new HttpClient();
console.log(http.apiUrl);  

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第27张图片
普通装饰器能做的,它也能做

接下来介绍:重载构造函数的例子

/*
   1.类装饰器
        下面是一个重载构造函数的例子
        类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数
        如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明 

*/
function logClass(target:any){ 
    console.log(target);
    
    return class extends target{
        apiUrl:any='我是修改后的值';

        getData(){
            this.apiUrl=this.apiUrl+'----'
            console.log(this.apiUrl);
        }
    }
}

@logClass
class HttpClient{
    public apiUrl:string | undefined;
    constructor(){
        this.apiUrl='我是构造函数里面的apiUrl'; 
    }
    getData(){
        console.log(this.apiUrl);
    }

}

var http=new HttpClient();
http.getData();

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第28张图片

属性装饰器

/**
 *  2.属性装饰器
 *      属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
 *          1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
 *          2.成员的名字 
 */

//类装饰器
function logClass(params:any){
    return function(target:any){  
        console.log(params);
        console.log(target);
      
    }
}

//属性装饰器
function logProperty(params:any){
    return function(target:any,attr:any){
        console.log(target);
        console.log(attr);

        target[attr]=params;//这是es6的写法
    } 
}

//@logClass('xxxx')
class HttpClient{

    @logProperty('http://baidu.com')
    public url:string | undefined;
    constructor(){
    }
    getData(){
        console.log(this.url);
    }
}
var http=new HttpClient();
http.getData();

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第29张图片

方法装饰器

方法装饰器
它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义

    方法修饰会再运行时传入下列3个参数:
        1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
        2.成员的名字
        3.成员的属性描述符
//方法装饰器1
function get(params:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target);
        console.log(methodName);
        console.log(desc);

        target.apiUrl='xxxx';
        target.run=function(){
            console.log('run');
        }
    }
}

class HttpClient{
    public url:string | undefined;
    constructor(){
    }
    @get('www.baidu.com')
    getData(){
        console.log(this.url);
    }
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.getData();

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第30张图片

//方法装饰器2
function get(params:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target);
        console.log(methodName);
        console.log(desc.value);

        //修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型

        //1.保存当前的方法
        var oMethod=desc.value;

        desc.value=function(...args:any[]){

            args=args.map((value)=>{
                return String(value);
            })

            console.log(args);
        }
    }
}

class HttpClient{
    public url:string | undefined;
    constructor(){
    }
    @get('www.baidu.com')
    getData(){
        console.log('我是getData里面的方法');
    }
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.getData(123,'xxx');

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第31张图片
稍微改造一下:

//方法装饰器2
function get(params:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target);
        console.log(methodName);
        console.log(desc.value);

        //修改装饰器的方法,把装饰器方法里面传入的所有参数改为string类型

        //1.保存当前的方法
        var oMethod=desc.value;

        desc.value=function(...args:any[]){

            args=args.map((value)=>{
                return String(value);
            })

            console.log(args);
            oMethod.apply(this,args);
        }
    }
}

class HttpClient{
    public url:string | undefined;
    constructor(){
    }
    @get('www.baidu.com')
    getData(...args:any[]){
        console.log(args);
        console.log('我是getData里面的方法');
    }
}
var http:any=new HttpClient();
console.log(http.apiUrl);
http.getData(123,'xxx');

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第32张图片

方法参数装饰器

参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:

        1. 对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
        2. 方法的名字
        3. 参数在函数列表种的索引
/*
    4.方法参数装饰器
        参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:

            1.对于静态成员来说是类的构造函数,对于实例成员来说是类的原型对象
            2.方法的名字
            3.参数在函数列表种的索引
 */

function logParams(params:any){
    return function(target:any,methodName:any,paramsIndex:any){
        console.log(params);
        console.log(target);
        console.log(methodName);
        console.log(paramsIndex);

        target.apiUrl=params;
    }
}

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

    }
    getData(@logParams('uid')uuid:any){
        
        console.log('我是getData里面的方法');
    }
 }

 var http:any=new HttpClient();
 http.getData(1231);
 console.log(http.apiUrl);

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第33张图片

装饰器执行顺序

 //装饰器执行顺序代码
 /*
    属性》方法》方法参数》类装饰器
    如果有多个同样的装饰器,它会先执行后面的
 */
function logClass1(params:string){//这里的params为传参的值
    return function(target:any){
        console.log('类装饰器1');
    }
}

function logClass2(params:string){//这里的params为传参的值
    return function(target:any){
        console.log('类装饰器1');
    }
}

//属性装饰器
function logAttribute(params?:string){ 
    return function(target:any,attrName:any){
        console.log('属性装饰器');
    }
}

//方法装饰器
function logMethod(params?:string){
    return function(target:any,attrName:any,desc:any){
        console.log('方法装饰器');
    }
}

//方法参数装饰器
function logParams1(params?:string){
    return function(target:any,attrName:any,desc:any){
        console.log('方法参数装饰器1');
    }
}

function logParams2(params?:string){
    return function(target:any,attrName:any,desc:any){
        console.log('方法参数装饰器2');
    }
}
    
    @logClass1('www.baidu.com')
    @logClass2('www.360.com')
    class HttpClient{

        @logAttribute()
        public apiUrl:string|undefined
        constructor(){
    
        }
        @logMethod()
        getData(){
            return true;
        }

        setData(@logParams1() attr1:any,@logParams2() attr2:any){

        }
    
    }
    
    var http:any=new HttpClient();

Typescript系统学习之监视代码,类型,类,接口,泛型使用,命名空间,装饰器笔记_第34张图片
执行顺序结论:

属性》方法》方法参数》类装饰器 如果有多个同样的装饰器,它会先执行后面的

附上本文笔记出自视频学习得来的视频教程地址:https://www.bilibili.com/video/BV1yt411e7xV

你可能感兴趣的:(typescript,typescript)