TS 泛型+装饰器

typescript 中的泛型

  1. 泛型的定义
  2. 泛型函数
  3. 泛型类
  4. 泛型接口

  • 泛型:软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统是为你提供了十分灵活的功能

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

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


泛型的定义
// 只能返回 string 类型的数据
function getData(value:string):string{
    return value
}

// 传入什么类型,就返回什么类型
// 泛型: 可以支持不特定的数据类型
// T 表示泛型,具体什么类型是调用方法是决定的
function getData(value:T):T{
    return value
}
getData('123')  // ×
getData(123)    // √

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

let m = new MinClass()
m.add(2)
m.add(3)
m.add(1)
alert(m.min())

类的泛型
// 类的泛型
class MinClass{
    public list:T[] = []
    add(value:T):void{
        this.list.push(value)
    }
    min():T{
        let minNum = this.list[0]
        for(let i = 0; i < this.list.length; i++){
            if(minNum > this.list[i]){
                minNum = this.list[i]
            }
        }
        return minNum
    }
}

let m = new MinClass()
m.add(2)
m.add(3)
m.add(1)
alert(m.min())

函数类型接口
/** 函数类型接口 规范 */
interface ConfigFn{
    (value1:string,value2:string):string
}

let setData:ConfigFn = function(value1:string,value2:string):string{
    return value1 + value2
}
setData("name","张三")

// 泛型接口
interface ConfigFn{
    (value1:T,value2:T):T
}

let setData:ConfigFn = function(value1:T,value2:T):T{
    return value1 + value2
}
setData("name","张三")
//----------------------------------------
interface ConfigFn{
    (value1:T,value2:T):T
}

function getData(value1:T,value2:T):T{
    return value1 + value2
}
let myGetData:ConfigFn = getData
myGetData("name","张三")

需求:定义一个操作数据库的库 支持 Mysql Mssql MongoDb

  • 要求1: Mysql Mssql MongoDb 功能一样,都有 add update delete get 方法
  • 注意:约束统一的规范、以及代码重用
  • 解决方案:需要约束规范所以要定义接口,需要代码重用所以用到泛型
    1. 接口:在面向对象的编程中,接口是规范的定义,它定义了行为和动作的规范
    1. 泛型:通俗的理解,泛型就是解决 类 接口 方法 的复用性
interface DBI{
    add(info:T):boolean
    update(info:T,id:number):boolean
    delete(id:number):boolean
    get(id:number):any[]
}

//定义一个操作mysql数据库的类
class MysqlDb implements DBI{
    add(info:T):boolean{
        
    }
    update(info:T,id:number):boolean{
        
    }
    delete(id:number):boolean{
        
    }
    get(id:number):any[]{
        
    }
}

//定义一个操作mssql数据库的类
class MssqlDb implements DBI{
    add(info:T):boolean{
        
    }
    update(info:T,id:number):boolean{
        
    }
    delete(id:number):boolean{
        
    }
    get(id:number):any[]{
        
    }
}

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

let u = new User()
u.username = '张三'
u.password = '123456'

let mysql = new MysqlDb() // 类作为参数来约束数据的类型
mysql.add(u)



ts模块

内部模块:命名空间

外部模块:模块

// db.ts
export function getData():any[]{
    return '数据'
}

// index.ts
import {getData} from './db'

// 命名空间  --> 避免命名重复
namespace A{    // 相当于私有的,需要暴露方法
    //代码
    export class Dog{
        name:string
        constructor(name:string){
            this.name = name
        }
        run(){
            console.log(this.name + "是dog")
        }
    }
}

let d = new A.Dog("xxx")
d.run()

namespace B{
    代码
}

装饰器

类装饰器:在不修改类的情况下扩展类的功能
// 普通装饰器 无参数
function logClass(params:any){
    conaole.log(params)
    // params 就是当前类
    params.prototype.apiUrl = 'xxx'
}

@logClass
class HttpClient{
    constructor(){
        
    }
    getData(){
        
    }
}

let h:any = new HttpClient()
console.log(h.apiUrl)
/////----------------------------------/////
// 装饰器工厂  可传参
function logClass(params:string){
    conaole.log(params)
    return function(target:any){
        console.log(target) // 当前类
        console.log(params) // http://xxx
        target.prototype.apiUrl = params
    }
}

@logClass('http://xxx')
class HttpClient{
    constructor(){
        
    }
    getData(){
        
    }
}

let h:any = new HttpClient()
console.log(h.apiUrl)

属性装饰器
function logProperty(params:any){
    return function(target:any,attr:any){
        console.log(target) // 当前类
        console.log(attr)   // url
        target[attr] = params   
    }
}

class HttpClient{
    @logProperty('http://xxx')
    public url:any | undefined
    
    constructor(){
        
    }
    getData(){
        
    }
}

let h:any = new HttpClient()
console.log(h.apiUrl)

方法装饰器

function logMethod(params:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target)
        console.log(methodName)
        console.log(desc)
        console.log(desc.value)
        target.apiUrl = 'xxx'
        target.run = function(){
            console.log('run')
        }
        let oMethod = desc.value
        desc.value = function(...args:any[]){
            args = args.map((value)=>{
                return String(value)
            })
            conaole.log(args)
            oMethod.apply(this,args)
        }
    }
}

class HttpClient{
    @logProperty('http://xxx')
    public url:any | undefined
    
    constructor(){}
    @logMethod("http://xxx")
    getData(...args:any){
        console.log('getData')
    }
}

执行顺序

属性装饰器 => 方法装饰器 => 方法参数装饰器2 => 方法参数装饰器1 => 类装饰器2 => 类装饰器1

同样的装饰器从后到前执行
END

你可能感兴趣的:(TS 泛型+装饰器)