Detailed tutorial typescript (b)

Detailed tutorial typescript (b)

Previous: typescript tutorials explain (a)

Seven, typescript generics

  /*  1. 泛型的定义 */
/*泛型,软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。组件不仅能够支持当前的数据类型
,同时也能支持未来的数据类型,这创建大型习时为你提供了十分灵活的功能。
在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据,这样用户就可以以自己
的数据类型来使用组件。
通俗理解,泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持。 
 */

/* 2. 泛型函数 */

//常规的只能返回string类型的数据
function getData1(value:string):string {
  return value;
}
// 泛型,可以支持不特定的数据类型 要求,传人的参数和返回的参数一致
// T表示泛型,具体什么类型是调用这个方法的时候决定的
// 第一种写法:
  function getData2<T>(value:T):T{
    return value
  }
  // 第二种写法:
  // function getData2<T>(value:T):any{
  //   return value
  // }
  getData2<number>(123);//参数必须是number

/* 3.泛型类: 比如有个最小堆算法,需要同时支持返回数字和字符串2种类型,通过类的泛型来实现*/
//这样是正常只能传人number
 /*  class MinClass{
    public list:number[]=[];
    add(num:number):void{
      this.list.push(num)
    }
    min():number{
      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
    }
  } */

  // 类的泛型
    class MinClass<T>{
    public list:T[]=[];
    add(num:T[]):void{
      this.list = num
    }
    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 m = new MinClass<number>() /* 实例化类,并定义类型 */
  m.add([1,2,3])
  console.log(m.min())

  /* 把类作为参数来约束数据传人的类型 */
/*   class User{
    userName:string|undefined;
    pasword:string| undefined;
  }

  class MysqlDb{
    add(user:User):boolean{
      return true
    }
  }

  var us = new User()
    us.userName = "张三"
    us.pasword = "123456"
    var db = new MysqlDb()
    db.add(us) */
    // 泛型实现
    class MysqlDb<T>{
      add(user:T):boolean{
        return true
      }
    }
    class User{
      userName:string|undefined;
      pasword:string| undefined;
    }
     var us = new User()
     us.userName = 'zhangsan'
      us.pasword = '1234'
   var Db = new MysqlDb<User>()
    Db.add(us)

    class Artcle {
      title:string|undefined;
      desc:string|undefined;
      constructor(params:{
        title:string|undefined,
        desc:string|undefined
      }){
        this.title = params.title
        this.desc = params.desc
      }
    }
    var art = new Artcle({
      title:'分类',
      desc:'111'
    })
    var Dbs = new MysqlDb<Artcle>()
    Dbs.add(art)
  

  // 泛型接口
  // 第一种写法:
  interface TconfigFn{
    <T>(value:T):T;
  }

  var getData:TconfigFn = function<T>(value:T):T{
    return value
  }
  getData<number>(123)
  // 第二种写法

  interface TconfigFn2<T>{
    (value:T):T;
  }

 function getData4<T>(value:T):T{
    return value
  }
  var myGetData:TconfigFn2<string> = getData4;

  myGetData('20')

Eight, typescript decorators

  /* 装饰器:装饰器是一种特殊的类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。
通俗的讲装饰器就是一个方法,可以注入到类,方法、属性参数上类扩展类、属性、方法、参数的功能。
常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)
装饰器是过去几年中js最多的成就之一,已是es7的标准特性之一
*/
//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)

// 装饰器工厂
function logClass1(params:string){

    return function(target:any){
      //装饰的类
      console.log(target)
target.prototype.apiUrl = params

      // 传人的参数
      console.log(params)
    }
}

@logClass1('传入参数')
class HttpClient1{
  constructor(){

  }
  getData(){

  }
}
var http1 :any = new HttpClient1();
console.log(http1.apiUrl)

/*
  类装饰器 重载构造函数
  重载需要全部重写,否则会报错
  类装饰表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
  如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
 */

function logClass2(params:any){

  return class extends params{
    apiUrl:any='我是修改后的数据';
    getData(){
      this.apiUrl = this.apiUrl+'---'
      console.log(this.apiUrl)
  }
  }

}

@logClass2
class HttpClient2{
  public apiUrl:string | undefined
constructor(){
  this.apiUrl = '我是构造函数里面的apiUrl'
 
}
getData(){
    console.log(this.apiUrl)
}
}
var http2 :any = new HttpClient2();
console.log(http1.apiUrl)

/*2. 属性装饰器 
  属性装饰器表达式会在运行时当做函数被调用,传人下列2个参数;
  1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  2成员名字。
*/
function logPropty(params:any){
  return function(target:any,attr:any){
      console.log(target,'类的原型对象')
      console.log(attr,'成员属性名')//apiUrl
      target[attr]=params
  }
}



class HttpClient3{
  @logPropty('http//:www/baidu.com')
  public apiUrl:string | undefined;
constructor(){

 
}
getData(){
    console.log(this.apiUrl)
}
}
var http3 :any = new HttpClient3();
http3.getData()


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

    方法装饰会在运行时传入下列3个参数:
      1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
      2.成员的名字
      3成员的属性描述符
*/
function logMethod(params:any){
  return function(target:any,methodName:any,desc:any){
    //修改装饰器的方法  把装饰器方法里面传入的所有参数改为string类型

    //1. 保存当前的方法
    var oMethod = desc.value;
    desc.value = function(...args:any[]){
      args  = args.map((value)=>{
        return String(value);
      })
      oMethod.apply(this.args);
      console.log(args)

    }
  }
}


class HttpClient4{

  public apiUrl:string | undefined;
constructor(){

 
}
@logMethod('http//:www/baidu.com')
getData(...args:any[]){
    console.log('我是内部方法')
}
}
var http4 :any = new HttpClient4();
http4.getData(123,'xxxx')


/* 方法参数装饰器(基本不适用)
  参数装饰器表达式会在运行时当做函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:

    1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
    2. 方法的名字
    3. 参数在函数参数列表中的索引
*/
function logParams(params:any){
  return function (target:any,methodName:any,index:any){
      target.apiUrl = params
  }
}

class HttpClient5{
constructor(){
 
}
getData(@logParams('http//:www/baidu.com')params:any){

    console.log(params)
}
}
var http5 :any = new HttpClient5();
http5.getData(11111)
console.log(http5.apiUrl)


// 装饰器执行顺序  先执行class内部,再执行外部类装饰器
/* 属性装饰器1
/* 属性装饰器2
  方法参数装饰器1(从右到左)
  方法参数装饰器2(从右到左)
  方法装饰器1
  方法装饰器2
  类装饰器2(从下到上)
  类装饰器1
*/
  function A (params:any){
    return function (target:any){
      console.log ('类装饰器1')
    }
  }
  function B (params:any){
    return function (target:any){
      console.log ('类装饰器2')
    }
  }
  function C1(params:any){
    return function (target:any,attr:any){
      console.log ('属性装饰器1')
    }
  }
  function C2 (params:any){
    return function (target:any,attr:any){
      console.log ('属性装饰器2')
    }
  }
  
  function D (params:any){
    return function (target:any,methodName:any,desc:any){
      console.log ('方法装饰器1')
    }
  }
  function E (params:any){
    return function (target:any,methodName:any,desc:any){
      console.log ('方法装饰器2')
    }
  }
  function F (params?:any){
    return function (target:any,methodName:any,index:any){
      console.log ('方法参数装饰器1')
    }
  }
  function G (params?:any){
    return function (target:any,methodName:any,index:any){
      console.log ('方法参数装饰器2')
    }
  }

  
@A('a')
@B('b')
class HttpClient6{
  @C1('C1')
  public params1: any
  @C2('c2')
  public params2: any
  constructor(){
   
  }
  @D('d')
  getData(@F()params:any,@G()params2:any){
  
  }
  @E('e')
   setData(){

   }
  }
  var http6 = new HttpClient6()

Nine, typescript modules and namespaces

/* 模块的概念
  我们可以把一些公共的功能单独抽离成一个文件作为一个模块。
  模块里面的变量 函数 类等默认是私有的,如果我们要在外部访问模块里面的数据(变量,函数,类),
  我们需要通过export暴露模块里面的数据(变量、函数、类...)
  暴露后我们通过import引入模块就可以使用模块里面暴露的数据(变量,函数,类)
*/

/* 命名空间概念
    命名空间:内部模块,主要用于组织代码,避免命名冲突。
    模块:ts的外部模块简称,侧重代码的复用,一个模块里可能会员多个命名空间
*/
/* 命名空间默认为私有,需要在外部使用需要export暴露 */
/* 命名空间模块化,可以通过正常的export和import引入
  也可以 ///<reference path ="modle.ts"/>
  这样就不需要export暴露命名空间(老版本方式)
*/
namespace A{
  interface Anima{
    name: string;
    eat(str:string):void;
  }
  export class Pig implements Anima{
    name:string;
    constructor(name:string){
      this.name = name;
    }
    eat(str:string){
      console.log(this.name+str)
    }
  }
  
}
namespace B{
  interface Anima{
    name: string;
    eat(str:string):void;
  }
  export class Pig implements Anima{
    name:string;
    constructor(name:string){
      this.name = name;
    }
    eat(str:string){
      console.log(this.name+str)
    }
  }
  
}
var pig = new A.Pig('小猪')
pig.eat('粮食')
块就可以使用模块里面暴露的数据(变量,函数,类)
*/

/* 命名空间概念
    命名空间:内部模块,主要用于组织代码,避免命名冲突。
    模块:ts的外部模块简称,侧重代码的复用,一个模块里可能会员多个命名空间
*/
/* 命名空间默认为私有,需要在外部使用需要export暴露 */
/* 命名空间模块化,可以通过正常的export和import引入
  也可以 ///<reference path ="modle.ts"/>
  这样就不需要export暴露命名空间(老版本方式)
*/
namespace A{
  interface Anima{
    name: string;
    eat(str:string):void;
  }
  export class Pig implements Anima{
    name:string;
    constructor(name:string){
      this.name = name;
    }
    eat(str:string){
      console.log(this.name+str)
    }
  }
  
}
namespace B{
  interface Anima{
    name: string;
    eat(str:string):void;
  }
  export class Pig implements Anima{
    name:string;
    constructor(name:string){
      this.name = name;
    }
    eat(str:string){
      console.log(this.name+str)
    }
  }
  
}
var pig = new A.Pig('小猪')
pig.eat('粮食')
Published 52 original articles · won praise 82 · views 30000 +

Guess you like

Origin blog.csdn.net/marendu/article/details/103194806