部分例子参考https://www.jianshu.com/p/f4c961cbb074

同名接口声明合并

interface InfoInter {
  name: string
  getRes(input: string): number
}

interface InfoInter {
  age: number
  getRes(input: number): string
}
// 相当于
interface InfoInter {
name:string
age:number
getRes(input:string):number
// +1 overload 
getRes(input: number): string
}

枚举,命名空间合并

enum Colors {
  red,
  green,
  pink
}
namespace Colors {
  export const yellow = 3
}
console.log(Colors)
//{0: "red", 1: "green", 2: "pink", red: 0, green: 1, pink: 2, yellow: 3}

装饰器

  • 提案阶段,慎用
  • 有4类装饰器:类装饰器,属性装饰器,参数装饰器,访问修饰器

类装饰器

类装饰器在类声明之前被声明,应用于类构造函数,可以监视、修改、替换类的定义,传入一个参数
function logClz(params:any) {
    console.log(params)  // class HttpClient
}
@logClz
class HttpClient {
    constructor() {

    }
}
// logClz() 接收的参数params就是被装饰的类HttpClient
  • HttpClient动态扩展属性属性和方法
function logClz(params:any) {
    params.prototype.url = 'xxxx';
    params.prototype.run = function() {
        console.log('run...');
    };
}
var http:any = new HttpClient();
http.run(); // run...

装饰器工厂:闭包形式


let sign = null
function setName(name: string) {
  return (target: new () => any) => {
    sign = target
    console.log(target.name)
  }
}
@setName('liu')
class ClassDec {}
console.log(sign === ClassDec) // true

在使用装饰器工厂时,如果不想给装饰器传参,可以把参数声明为可选参数,但使用装饰器时仍然不能丢失小括号!

@setName()

属性装饰器

  • 属性装饰器表达式会在运行时当作函数被调用,传入两个参数
  • 成员的名字;
function logProp(params:any) {
    return function(target:any, attr:any) {
        console.log(target)  // { constructor:f, getData:f } 
        console.log(attr)  // url
        target[attr] = params;  //通过原型对象修改属性值 = 装饰器传入的参数
        target.api = 'xxxxx';  //扩展属性
        target.run = function() {  //扩展方法
            console.log('run...');
        }
    }
}
class HttpClient {
    @logProp('http://baidu.com')
    public url:any|undefined;
    constructor() { }
    getData() {
        console.log(this.url);
    }
}
var http:any = new HttpClient();
http.getData();  // http://baidu.com
console.log(http.api);  // xxxxx
http.run();  // run...

方法修饰器

  • 运行时被当做函数调用,有3个参数。
  • 第一个参数:装饰静态成员时,代表类构造函数;装饰实例时,代表类的原型对象
  • 第二个参数:  成员名
  • 第三个参数 成员属性描述符 : configurable 可配置 writeable 可写 enumerable 可枚举
  • 使用Object.defineProperty改写属性描述符

interface Objex {
  [key: string]: any
}
let obj12: Objex = {
  age: '123'
}

Object.defineProperty(obj12, 'name', {
  value: 'chen',
  configurable: true,
  writable: true,
  enumerable: true
})
obj12.name = 'XXXXXXXXXXXX'
console.log(obj12.name)

for (const key in obj12) {
  console.log(key)
}

方法参数修饰器

参数定义同上 方法修饰器

function required(target: any, properName: string, index: number) {
  console.log(`修饰${properName}的${index + 1}`)
}
class ClassI {
  public name: string = 'lzw'
  public age: number = 24
  public getInfo(prefix: string, @required infoType: string): any {
    return prefix + ' ' + this[infoType]
  }
}
interface ClassI {
  [key: string]: string | number | Function
}

装饰器的执行顺序

在TypeScript里,当多个装饰器应用在一个声明上时会进行如下步骤的操作:

  1. 由上至下依次对装饰器表达式求值;
  2. 求值的结果会被当作函数,由下至上依次调用.
  3. 不同装饰器的执行顺序:属性装饰器 > 方法装饰器 > 参数装饰器 > 类装饰器


爬。