zoukankan      html  css  js  c++  java
  • Typescript

    一、环境配置

    1、安装

    # npm 安装
    npm install -g typescript
    
    # 淘宝安装
    # npm install -g cnpm --registry=https://registry.npm.taobao.org
    cnpm install -g typescript
    
    # yarn安装
    # npm install -g yarn
    # cnpm install -g yarn
    yarn global add typescript
    

    2、验证安装

    tsc -v
    

    3、配置自动编译

    • 创建tsconfig.json文件

      tsc --init
      
    • 修改配置文件

      {
        "compilerOptions": {
          ...
          "outDir": "./js",
          ...
        }
      }
      
    • VSCODE编辑器 -- 终端 -- 运行任务 -- tsc:监视-tsconfig.json(VSCODE新版本)

    • VSCODE编辑器 -- 任务 -- 运行任务 -- tsc:监视-tsconfig.json(VSCODE老版本)

    二、数据类型

    1、布尔类型(boolean)

    var flag:boolean = true;
    flag = false;
    

    2、数字类型(number)

    var a:number = 123;
    a = 12.3;
    

    3、字符串类型(string)

    var str:string = 'this is ts'
    str = '你好 ts'
    

    4、数组类型(array)

    /* 第一种定义数据的方式 */
    let arrNumber:number[] = [1,2,3,4]; // 数字数组,只能放数字类型
    let arrString:string[]=["java","javascript"]; // 字符串数组,只能放字符串
    
    /* 第二种定义数据的方式 */
    let arrNumber:Array<number> = [11,22,33]; // 泛型定义数字数组
    let arrString:Array<string> = ["java","javascript"]; // 泛型定义字符串数组
    
    /* 第三种定义数据的方式 */
    let arrAny:any[] = [123,'123',true];
    

    5、元组类型(tuple)

    // 元组类型(tuple) 属于数组的一种
    // 可以在数组中,指定多个数据类型,但是类型要一一对应
    let arr:[string,number,boolean] = ["ts",13.18,true];
    
    // let arr:[string,number,boolean] = ["ts",13.18,true,111]; 错误写法
    // 不能将类型“[string, number, true, number]”分配给类型“[string, number, boolean]”
    // 源具有 4 个元素,但目标仅允许 3 个。
    

    6、枚举类型(enum)

    /*
    	enum 枚举名 {
    		标识符[=整型常数],
    		标识符[=整型常数],
    		...
    		标识符[=整型常数],
    	};
    */
    // 1、元素赋值,输出被赋予的值
    enum Flag {
        success=1,
        error=-1
    }
    var f:Flag = Flag.success; // 打印f,输出1
    // 2、元素不赋值,输出元素索引值,从0开始
    enum Color {red,blue,orange};
    var c:Color = Color.blue; // 打印c,输出1.
    // 3、元素既有赋值,又有未赋值
    // 3-1、blue赋值为数字,则orange+1
    enum Color {red,blue=5,orange};
    Color.blue; // 输出5
    Color.orange; // 输出6
    // 3-2、blue赋值为字符串,则orange也要为字符串,否则报错
    enum Color {red,blue="a",orange="b"};
    Color.blue; // 输出 a
    Color.orange; // 输出 b
    

    7、任意类型(any)

    var num:any = 123;
    num = "123"; // 不报错
    num = true; // 不报错
    

    8、null和undefined

    其他(never类型)数据类型的子类型

    var num1:number;
    console.log(num1); // 报错
    
    var num2:undefined;
    console.log(num2); // 虽然未定值,但是可以运行
    
    var num3:number | undefined;
    num3 = 123;
    console.log(num3); // 123
    
    var num4:number | undefined;
    console.log(num4); // undefined
    
    var num5:null;
    num5 = 123; // 报错
    num5 = null; // 无报错
    
    var num6:number | undefined | null;
    num6 = 123;
    console.log(num6); // 123
    

    9、void

    /* typescript中的void表示:
     * 		没有任何类型,一般用于定义方法的时候方法没有返回值
     */
    
    // 表示函数没有任何返回类型
    function run():void {
        console.log('run')
    }
    

    10、never

    /*
    	never类型:
    	是其他类型(包括:null和undefined)的子类型,代表从不会出现的值。
        意味着声明never的变量只能被never类型所赋值
    */
    
    var a:undefined;
    a=undefined;
    
    var b:null;
    b=null;
    
    var c:never;
    // c = 123; // 错误写法
    a = (()=>{
        throw new Error('错误');
    })()
    

    三、函数

    1、函数的定义

    /* 函数声明法 */
    function run():string {
        return 'run';
    }
    /* 匿名函数 */
    var fun2 = function():number{
        return 123;
    }
    /* 定义方法传参 */
    function getInfo(name:string, age:number):string {
        return `${name} --- ${age}`;
    }
    var getInfo2 = function(name:string, age:number):string{
        return `${name} --- ${age}`;
    }
    /* 没有返回值 */
    function run:void{
        console.log('run');
    }
    

    2、方法可选参数

    // es5中方法的实参和形参可以不一样
    // ts中必须一样,如果不一样就需要配置可选参数
    function getInfo(name:string, age?:number):string {
        if(age) {
            return `${name} --- ${age}`;
        } else {
            return return `${name} --- 年龄保密`;
        }
    }
    
    console.log(getInfo('张三',20)) // 张三 --- 20
    console.log(getInfo('张三')) // 张三 --- 年龄保密
    
    /* 可选参数必须配置到参数的最后边 */
    

    3、默认参数

    // es5里无法设置默认参数
    // es6和ts中都可以设置默认参数
    function getInfo(name:string, age:number=20):string {
        return `${name} --- ${age}`;
    }
    console.log(getInfo('张三',30)) // 张三 --- 30
    console.log(getInfo('张三')) // 张三 --- 20
    

    4、剩余参数

    // 以下方法只能接收4个参数,调用时超出,则报错
    function sum(a:number,b:number,c:number,d:number):number {
        return a+b+c+d;
    }
    sum(1,2,3,4)
    
    // 三点运算符 接收新参传过来的值
    function sum(...result:number[]):number {
        var sum = 0;
        for(var i=0;i<result.length;i += 1){
            sum += result[i]
        }
        return sum;
    }
    sum(1,2,3,4,5,6)
    
    // 改写1
    function sum(a:number,...result:number[]):number {
        var sum = a;
        for(var i=0;i<result.length;i += 1){
            sum += result[i]
        }
        return sum;
    }
    sum(1,2,3,4,5,6)
    

    5、函数重载

    // java中的重载:重载指的是两个或两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。
    // typescript中的重载:通过为同一个函数提供多个函数类型定义来实现多种功能的目的。
    // ts为了兼容es5和es6重载的写法和java中有区别
    
    // es5中出现同名方法,下面的会替换上面的方法
    function css(config){}
    function css(config,value):any{}
    
    // 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 + 1;
        }
    }
    

    6、箭头函数

    setTimeout(function(){alert('run')},1000)
    
    // 箭头函数中的this指向上下文
    setTimeout(()=>{alert('run')},1000)
    

    四、类

    1、es5中的类

    /* 
    	一、最简单的类 
     */
    function Person(){
        this.name = '张三';
        this.age = 20;
    }
    var p = new Person();
    console.log(p.name); // 张三
    
    /*********************************************************/
    
    /* 
    	二、构造函数和原型链里面增加方法
    */
    function Person(){
        this.name = '张三';
        this.age = 20;
        this.run = function() {
            console.log(`${this.name}在运动`)
        }
    }
    // 原型链上的属性会被多个实例共享,构造函数不会
    Person.prototype.sex = '男';
    Person.prototype.work = function() {
         console.log(`${this.name}在工作`)
    }
    var p = new Person();
    // run是实例方法,需要new Person()
    p.run(); // 张三在运动
    p.work(); // 张三在工作
    
    /*********************************************************/
    
    /* 
    	三、类中的静态方法
    */
    Person.getInfo = function() {
        console.log('我是静态方法');
    }
    // getInfo是静态方法,无需new,直接调用即可
    Person.getInfo(); // 我是静态方法
    
    /*********************************************************/
    
    /* 
    	四、es5中的继承
    */
    // 定义person类
    function Person(){
        this.name = '张三';
        this.age = 20;
        this.run = function() {
            console.log(`${this.name}在运动`)
        }
    }
    Person.prototype.sex = '男';
    Person.prototype.work = function() {
         console.log(`${this.name}在工作`)
    }
    
    # 对象冒充实现继承
    // web类 继承Person类 
    function Web(){
        Person.call(this); // 对象冒充实现继承
    }
    var w = new Web();
    w.run(); // 对象冒充可以继承构造函数中的属性和方法
    w.work(); // 报错。对象冒充无法继承原型链上的属性和方法
    
    # 原型链实现继承
    // web类 继承Person类 
    function Web(){}
    Web.prototype = new Person(); // 原型链实现继承
    var w = new Web();
    w.work(); // 张三在工作
    
    # 原型链确实可以继承Person的构造属性和方法,还有原型链上的属性和方法,但是存在问题。
    // 重新定义Person
    function Person(name,age){
        this.name = name;
        this.age = age;
        this.run = function() {
            console.log(`${this.name}在运动`)
        }
    }
    Person.prototype.sex = '男';
    Person.prototype.work = function() {
         console.log(`${this.name}在工作`)
    }
    
    function Web(){}
    Web.prototype = new Person();
    # 实例化子类的时候没法给父类传参
    var w = new Web('赵四',30); 
    w.run(); // undefined在运动
    
    # 原型链 + 构造函数的组合继承模式(总结方式一)
    // 定义Person
    function Person(name,age){
        this.name = name;
        this.age = age;
        this.run = function() {
            console.log(`${this.name}在运动`)
        }
    }
    Person.prototype.sex = '男';
    Person.prototype.work = function() {
         console.log(`${this.name}在工作`)
    }
    
    function Web(name,age){
        Person.call(this,name,age); // 对象冒充继承。实例化子类可以给父类传参
    }
    Web.prototype = new Person();
    var w = new Web('赵四',30); 
    w.run(); // 赵四在运动
    w.work(); // 赵四在工作
    
    # 原型链 + 构造函数的组合继承模式(总结方式二)
    // 定义Person
    function Person(name,age){
        this.name = name;
        this.age = age;
        this.run = function() {
            console.log(`${this.name}在运动`)
        }
    }
    Person.prototype.sex = '男';
    Person.prototype.work = function() {
         console.log(`${this.name}在工作`)
    }
    
    function Web(name,age){
        Person.call(this,name,age); // 对象冒充继承。实例化子类可以给父类传参
    }
    Web.prototype = Person.prototype;
    var w = new Web('赵四',30); 
    w.run(); // 赵四在运动
    w.work(); // 赵四在工作
    

    2、typescript中的类

    # ts中定义类 1 #
    class Person {
        name: string; // 前面省略了public关键字
    	
    	constructor(n:string){ // 构造函数,实例化类的时候触发的方法
            this.name = n;
        }
    
    	run():void{
            console.log(this.name)
        }
    }
    
    var p = new Person('张三');
    p.run(); // 张三
    
    # ts中定义类 2 #
    class Person {
        name: string; // 前面省略了public关键字
    	
    	constructor(n:string){ // 构造函数,实例化类的时候触发的方法
            this.name = n;
        }
    
    	getName():string {
            return this.name;
        }
    
    	setName(name):void {
            this.name = name;
        }
    }
    var p = new Person('张三');
    console.log(p.getName()) // 张三
    p.setName('李四');
    console.log(p.getName()) // 李四
    

    3、typescript实现继承

    // extends super
    class Person {
        name;string;
        constructor(name:string) {
            this.name = name;
        }
        run():string{
            return `${this.name}在运动`;
        }
    }
    
    class Web extends Person {
        constructor(name:string){
            super(name);
        }
        work(){
            console.log(`${this.name}在工作`)
        }
    }
    var w = new Web('李四');
    console.log(w.run()); // 李四在运动
    w.work(); // 李四在工作
    
    class Web extends Person {
        constructor(name:string){
            super(name);
        }
        run():string{
            return `${this.name}在运动--子类`;
        }
        work(){
            console.log(`${this.name}在工作`)
        }
    }
    // 字类与父类有同名方法,执行字类自己的方法
    console.log(w.run()); // 李四在运动--子类
    

    4、typescript类中的修饰符

    修饰符 类中是否可访问 子类是否可访问 类外是否可访问
    public
    protected
    private

    5、typescript的静态属性和静态方法

    class Person {
        public name: string;
    	static gender:string = "男"; // 静态属性
    	constructor(name:string){
            this.name = name;
        }
    	run():string {
            return `${this.name}在运动`;
        }
    	static print() { // 静态方法
    		console.log('print')
    	}
    }
    Person.print(); // print
    console.log(Person.gender); // 
    

    6、typescript的多态

    // 多态:父类定义一个方法不去实现,让继承它的子类去实现,每一个子类有不同的表现
    // 多态属于继承
    
    // 动物类
    class Animal {
        name:string;
        constructor(name:string){
            this.name = name;
        }
        eat(){
            console.log('eat')
        }
    }
    // 狗
    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 + '吃鱼'
        }
    }
    

    7、typescript的抽象方法

    // 用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
    // abstract 抽象方法只能放在抽象类中
    // 抽象类和抽象方法用来定义标准
    
    abstract class Animal{
        name:string;
        constructor(name:string){
            this.name = name;
        }
        abstract eat():any;
    }
    
    class Dog extends Animal {
        constructor(name:string){
            super(name);
        }
        // 抽象类的子类必须实现抽象类里面的抽象方法
        eat(){
            console.log(this.name + '吃肉')
        }
    }
    

    五、接口

    1、属性接口

    // 对json的约束
    
    /* 对传入对象的约束 属性接口 */
    interface Fullname {
        firstName:string; // 分号结束
        secondName:string;
    }
    
    function printName(name: Fullname){
        // 必须传入对象 firstName secondName
        console.log(name.firstName + '---' + name.secondName)
    }
    
    /* 对批量方法进行约束 */
    printName({
        firstName:'张',
        secondName:'三',
        age:30
    }) // 报错
    printName({
        firstName:'张',
        secondName:'三'
    }) // 正常
    var obj = {
        firstName:'张',
        secondName:'三',
        age:30
    }
    printName(obj) // 正常
    

    1-1、可选属性

    interface Fullname {
        firstName:string; // 分号结束
        secondName?:string;
    }
    function printName(name: Fullname){
        // 必须传入对象 firstName secondName
        console.log(name.firstName + '---' + name.secondName)
    }
    printName({
        firstName:'张'
    }) // 正常。无需再传secondName。因为secondName可选
    

    1-2、案例

    /* 原生js封装ajax,不兼容IE6 */
    
    // ajax请求数据接口
    interface Config {
        type: string;
        url:string;
        data?:string;
        dataType:string;
    }
    
    function ajax(config: Config) {
        var xht = 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('成功');
                if(config.dataType == 'json'){
                    console.log(JSON.parse(xhr.responseText))
                }else {
                    console.log(xhr.resposeText)
                }
            }
        }
    }
    
    ajax({
        type: 'get',
        url: 'http://api',
        dataType: 'json'
    })
    
    ajax({
        type: 'get',
        data: 'name=zhangsan'
        url: 'http://api',
        dataType: 'json'
    })
    

    2、函数类型接口

    // 函数类型接口:对方法传入的参数以及返回值进行约束 批量约束
    
    /* 加密的函数类型接口 */
    interface encrypt{
        (key:string,value:string):string;
    }
    
    var md5: encrypt = function(key:string,value:string):string{
        // 模拟操作
        return key+value;
    }
    
    console.log(md5('name','zhangsan'))
    

    3、可索引接口

    # 可索引接口:数组、对象的约束(不常用)
    
    // 对数组约束
    interface UserArr {
        [index:number]:string
    }
    var arr:UserArr = ['123','124']
    
    // 对对象约束
    interface UserObj {
        [index:string]:string
    }
    var arr:UserObj = {name:'张三'}
    

    4、类类型接口

    # 类类型接口:对类的约束,和抽象类比较相似
    
    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;
    	contructor(name:string) {
            this.name = name;
        }
    	eat(food:string){
            console.log(this.name + '吃' + food)
        }
    }
    
    var c = new Cat('小花');
    c.eat('鱼')
    

    5、接口扩展

    # 接口扩展:接口可以继承接口
    
    interface Animal{
        eat():void;
    }
    
    interface Person extends Animal {
        work():void;
    }
    
    class Web implements Person{
        public name:string;
    	contructor(name:string){
            this.name = name;
        }
    	eat(){
            console.log(this.name+'喜欢吃馒头')
        }
    	work(){
            console.log(this.name+'敲代码')
        }
    }
    
    var w = new Web('小磊');
    w.work();
    w.eat();
    
    # extends implements 结合使用
    
    interface Animal{
        eat():void;
    }
    
    interface Person extends Animal {
        work():void;
    }
    
    class programmer {
        public name:string;
    	contructor(name:string) {
            this.name = name;
        }
    	coding(code:string){
            console.log(this.name+code)
        }
    }
    
    class Web extends programmer implements Person {
        contructor(name:string){
            super(name)
        }
        eat(){
            console.log(this.name+'喜欢吃馒头')
        }
    	work(){
            console.log(this.name+'敲代码')
        }
    }
    var w = new Web('小磊');
    w.coding('写ts代码')
    

    六、泛型

    1、泛型函数

    // 以下只能返回string类型的数据
    function getData(value:string):string {
        return value;
    }
    // 同时返回string 类型 和 number类型 (代码冗余)
    function getData1(value:string):string {
        return value;
    }
    function getData2(value:number):number {
        return value;
    }
    // 同时返回string 类型 和 number类型 (可能传入number,但是返回string。放弃了类型检查)
    function getData3(value:any):any {
        return value;
    }
    // 泛型:可以支持不特定的数据类型。要求:传入的参数和返回的参数一致
    // T表示泛型,具体什么类型是调用方法的时候决定的
    function getData3<T>(value:T):T {
        return value;
    }
    getData<string>('abc')
    getData<number>(123)
    

    2、泛型类

    # 泛型类:比如有个最小堆算法,需要同时支持返回数字和字符串两种类型。通过类的泛型来实现。
    
    // 只支持number的MinClass
    class MinClass {
        public list:number[]=[];
    	add(num:number) {
            this.list.push(num)
        }
    	min():number{
            var minNum = this.list[0];
            for(var i=0;i<this.list.length;i+=1){
                if(minNum > this.list[i]){
                    minNum = this.list[i];
                }
            }
            return minNum;
        }
    }
    var m = new MinClass();
    m.add(2);
    m.add(3);
    m.add(4);
    console.log(m.min);
    
    // 泛型改造
    class MinClass<T> {
        public list:T[]=[];
    	add(num:T) {
            this.list.push(num)
        }
    	min():T{
            var minNum = this.list[0];
            for(var i=0;i<this.list.length;i+=1){
                if(minNum > this.list[i]){
                    minNum = this.list[i];
                }
            }
            return minNum;
        }
    }
    

    3、泛型接口

    // 函数类型接口
    interface Configfn {
        (value1:string,value2:string):string
    }
    var setData:Configfn = function(value1:string,value2:string):string{
        return value1 + value2;
    }
    
    // 泛型改造1
    interface Configfn {
        <T>(value1:T):T
    }
    var getData:Configfn = function<T>(value:T):T{
        return value;
    }
    getData<string>('张三')
    
    // 泛型改造2
    interface Configfn {
        <T>(value1:T):T
    }
    function getData<T>(value:T):T{
        return value;
    }
    var myGetData:Configfn<string>=getData;
    myGetData('20')
    

    4、泛型类拓展

    // 把类作为参数来约束数据传入的类型
    class User {
        username: string | undefined; // 为保证username不被赋值时不报错,需要加入undefined类型
    	password: string | undefined;
    }
    
    class MysqlDb {
        add(user:User):boolean {
            return true;
        }
    }
    var u = new User();
    u.username = '张三';
    u.password = '123456';
    var Db = new MysqlDb();
    Db.add(u);
    
    // 泛型改造
    class Article<T> {
        title: string | undefined;
    	describe: string | undefined;
    	status: number | undefined;
    }
    class MysqlDb {
        add(info:T):boolean {
            return true;
        }
    }
    var a = new Article();
    a.title = '标题';
    a.describe = '描述';
    a.status = 1;
    var Db = new MysqlDb<Article>();
    Db.add(a);
    

    七、综合使用

    1、封装统一操作(Mysql|Mongodb|Mssql)

    interface DBI<T> {
        add(info:T):boolean;
        update(info:T,id:number):boolean;
        delete(id:number):boolean;
        get(id:number):any[];
    }
    # 要实现泛型接口,这个类应该也是一个泛型类
    // 定义操作mysql数据库的类
    class MysqlDb<T> implements DBI<T> {
        add(info: T): boolean {
            throw new Error("Method not implemented.");
        }
        update(info: T, id: number): boolean {
            throw new Error("Method not implemented.");
        }
        delete(id: number): boolean {
            throw new Error("Method not implemented.");
        }
        get(id: number): any[] {
            throw new Error("Method not implemented.");
        }
    }
    
    class MsSqlDb<T> implements DBI<T> {
        add(info: T): boolean {
            throw new Error("Method not implemented.");
        }
        update(info: T, id: number): boolean {
            throw new Error("Method not implemented.");
        }
        delete(id: number): boolean {
            throw new Error("Method not implemented.");
        }
        get(id: number): any[] {
            throw new Error("Method not implemented.");
        }
    }
    
    class User {
        username: string | undefined;
    	password: string | undefined;
    }
    
    var u = new User();
    u.username = '张三';
    u.password = '123456';
    
    var omysql = new MysqlDb<User>();
    omysql.add(u);
    

    八、模块

    // ./modules/db.ts
    var dbUrl = 'xxx';
    export function getData():any[] {
        console.log('获取数据库数据');
        return [
            {title:'123'},
            {title:'124'}
        ]
    }
    export function save():void {
        console.log('保存成功')
    }
    
    // 引入
    import { getData,save } from './modules/db'
    getData();
    save();
    
    // 另外一种暴露数据的方法
    // ./modules/db.ts
    var dbUrl = 'xxx';
    function getData():any[] {
        console.log('获取数据库数据');
        return [
            {title:'123'},
            {title:'124'}
        ]
    }
    function save():void {
        console.log('保存成功')
    }
    export {dbUrl,getData,save}
    
    // 引入
    import { getData as get,save } from './modules/db'
    get();
    save();
    
    // export default:只能用一次
    // ./modules/db.ts
    var dbUrl = 'xxx';
    function getData():any[] {
        console.log('获取数据库数据');
        return [
            {title:'123'},
            {title:'124'}
        ]
    }
    function save():void {
        console.log('保存成功')
    }
    export default getData;
    
    // 引入
    import getData from './modules/db'
    getData();
    

    九、命名空间

    // 命名空间:内部模块,主要用于组织代码,避免命名冲突
    // 模块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间
    namespace A {
        interface Animal {
            name: string | undefined;
            eat(): void;
        }
    
        export class Dog implements Animal {
            name: string | undefined;
            constructor(theName:string){
                this.name = theName;
            }
            eat(): void {
                console.log(`${this.name}吃狗粮`);
            }
        }
    
        export class Cat implements Animal {
            name: string | undefined;
            constructor(theName:string){
                this.name = theName;
            }
            eat(): void {
                console.log(`${this.name}吃猫粮`);
            }
        }
    }
    
    namespace B {
        interface Animal {
            name: string | undefined;
            eat(): void;
        }
    
        export class Dog implements Animal {
            name: string | undefined;
            constructor(theName:string){
                this.name = theName;
            }
            eat(): void {
                console.log(`${this.name}吃狗粮`);
            }
        }
    
        export class Cat implements Animal {
            name: string | undefined;
            constructor(theName:string){
                this.name = theName;
            }
            eat(): void {
                console.log(`${this.name}吃猫粮`);
            }
        }
    }
    
    var d = new A.Dog('狗'); // 命名空间A的Dog类
    d.eat();
    
    var c = new B.Cat('猫'); // 命名空间B的Cat类
    c.eat();
    

    9-1、模块化

    export namespace A {
        interface Animal {
            name: string | undefined;
            eat(): void;
        }
    
        export class Dog implements Animal {
            name: string | undefined;
            constructor(theName:string){
                this.name = theName;
            }
            eat(): void {
                console.log(`${this.name}吃狗粮`);
            }
        }
    
        export class Cat implements Animal {
            name: string | undefined;
            constructor(theName:string){
                this.name = theName;
            }
            eat(): void {
                console.log(`${this.name}吃猫粮`);
            }
        }
    }
    
    export namespace B {
        interface Animal {
            name: string | undefined;
            eat(): void;
        }
    
        export class Dog implements Animal {
            name: string | undefined;
            constructor(theName:string){
                this.name = theName;
            }
            eat(): void {
                console.log(`${this.name}吃狗粮`);
            }
        }
    
        export class Cat implements Animal {
            name: string | undefined;
            constructor(theName:string){
                this.name = theName;
            }
            eat(): void {
                console.log(`${this.name}吃猫粮`);
            }
        }
    }
        
    // 引入
    import {A} from './a'
    var d = new A.Dog('狗');
    d.eat();
    

    十、装饰器

    1、普通装饰器(不带参数)

    // 装饰器
    function logClass(params:any){
        console.log(params); // params就是当前类
        params.prototype.apiUrl = 'urlxxx';
        params.prototype.run = function(){
            console.log('run');
            
        }
    }
    @logClass
    class HttpClient {
        constructor(){}
        getData(){}
    }
    var http:any = new HttpClient();
    console.log(http.apiUrl);
    http.run();
    

    2、装饰器工厂(可传参)

    function logClass(params:string){
        return function(target:any){
            console.log(target);
            console.log(params);
            target.prototype.apiUrl = params;
        }
    }
    
    @logClass('http://api')
    class HttpClient {
        constructor(){}
        getData(){}
    }
    
    var http:any = new HttpClient();
    console.log(http.apiUrl);
    

    3、修改类中的构造函数和构造方法

    function logClass(target:any){
        console.log(target);
        // 重写HttpClient函数的构造函数和构造方法
        return class extends target {
            apiUrl:any = '我是修改后的数据';
            getData(){
                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();
    

    4、属性装饰器

    // 属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数
    // 	1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
    //	2、成员的名字
    
    // 类装饰器
    function logClass(params:string){
        return function(target:any){
            // console.log(target);
            // console.log(params);
        }
    }
    // 属性装饰器
    function logProperty(params:any){
        return function(target:any,attr:any){
            console.log(target);
            console.log(attr);
            target[attr] = params;
        }
    }
    
    @logClass('http://api')
    class HttpClient {
        @logProperty('http://api')
        public url:any | undefined;
        constructor(){}
        getData(){
            console.log(this.url);
        }
    }
    
    var http = new HttpClient();
    http.getData();
    

    5、方法装饰器

    // 发放装饰器
    // 应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义
    // 方法装饰会在运行时传入下列3个参数
    //		1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
    //		2、成员的名字
    //		3、成员的属性描述符
    
    function get(params:any){
        return function(target:any,methodName:any,describe:any){
            console.log(target);
            console.log(methodName);
            console.log(describe);
    
            target.apiUrl = 'xxxx';
            target.run = function(){
                console.log('run');
                
            }
        }
    }
    
    class HttpClient {
        public url:any | undefined;
        constructor(){}
        @get('http://www.baidu.com')
        getData(){
            console.log(this.url);
        }
    }
    
    var http:any = new HttpClient();
    console.log(http.apiUrl);
    http.run();
    

    5-1、修改方法

    function get(params:any){
        return function(target:any,methodName:any,describe:any){
            console.log(target);
            console.log(methodName);
            console.log(describe.value);
            // 修改装饰器方法 把装饰器方法里面传入的所有参数改为stringl类型
            // 保存当前的方法
            var oMethod = describe.value;
            describe.value = function(...args:any[]){
                args = args.map((value)=>{
                    return String(value);
                })
                console.log(args);
            }
        }
    }
    
    class HttpClient {
        public url:any | undefined;
        constructor(){}
        @get('http://www.baidu.com')
        getData(){
            console.log('我是getData的方法');
        }
    }
    
    var http:any = new HttpClient();
    http.getData(123,'xxxx');
    

    6、方法参数装饰器

    // 方法参数装饰器
    // 参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:
    // 	1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
    //	2、方法的名字
    // 	3、参数在函数参数列表中的索引
    function logParams(params:any){
        console.log(params);
        return function(target:any,methodName:any,paramIndex:any){
            console.log(target);
            console.log(methodName);
            console.log(paramIndex);
    
            target.apiUrl = params;
        }
    }
    class HttpClient {
        public url:any | undefined;
        constructor(){}
        getData(@logParams('xxxxx') uuid:any){
            console.log('我是getData的方法');
        }
    }
    
    var http:any = new HttpClient();
    http.getData(123456);
    console.log(http.apiUrl);
    

    7、装饰器的执行顺序

    function logClass1(params:string){
        return function(target:any){
            console.log('类装饰器1');
        }
    }
    function logClass2(params:string){
        return function(target:any){
            console.log('类装饰器2');
        }
    }
    function logAttribute(params?:string){
        return function(target:any,attrName:any){
            console.log('属性装饰器');
        }
    }
    
    function logMethod(params?:string){
        return function(target:any,methodName:any,describe:any){
            console.log('方法装饰器');
        }
    }
    
    function logParams1(params?:string){
        return function(target:any,methodName:any,paramIndex:any){
            console.log('参数装饰器1');
        }
    }
    
    function logParams2(params?:string){
        return function(target:any,methodName:any,paramIndex:any){
            console.log('参数装饰器2');
        }
    }
    
    @logClass1('class1')
    @logClass2('class2')
    class HttpClient {
        @logAttribute()
        public url:any | undefined;
        constructor(){}
        @logMethod()
        getData(){
            return true;
        }
        setData(@logParams1() attr1:any,@logParams2() attr2:any){}
    }
    
    属性装饰器 
    方法装饰器 
    参数装饰器2
    参数装饰器1
    类装饰器2  
    类装饰器1 
    
    
    属性 》 方法 》 方法参数 》 类
    如果有多个同样装饰器,会先执行后边的
    

    学习自Typescript教程_Typescript视频教程 ts入门实战视频教程-2020年4月更新

  • 相关阅读:
    【面试突击】-RabbitMQ常见面试题(一)
    并发艺术--java并发编程基础
    并发艺术--java内存模型
    并发艺术--java并发机制的底层实现原理
    并发艺术--并发编程挑战
    Spring Boot 项目中的 parent
    封装关于金额计算的double工具类
    日期和字符串类型相互转换工具类
    统一封装json返回结果
    Hibernate-validator数据验证
  • 原文地址:https://www.cnblogs.com/luckyzs/p/14212882.html
Copyright © 2011-2022 走看看