ts的基础(3)

(二十一)declare

声明文件  xxx.d.ts

在使用第三方时,必须有声明文件,不然会报错。

一些火的库,社区会编写声明文件, npm i -S @types/xxxx 。(比如echarts)

比较冷门的库,没有人编写声明文件,就需要手写声明文件。(比如旧版的express,现在有了)

如果没有,那就需要创建一个xx.d.ts文件,这里放在了typings下。

//express.d.ts


declare module 'express'{  // 手写一个声明文件,express这个是很简单的写法

  interface Router{
    get(path:string,cb:(req:any,res:any)=>void):void
  }

  interface App {
    use:(path:string,router:any)=>void
    listen(port:number,cb?:()=>void)
  }

  interface Express{
    ():App
    Router():Router
  }

  const express : Express

  export default express
}

还可以扩充全局变量
declare var qun:number
// 全局函数
declare function xxx(params:type) {

}
// 全局类,枚举,命名空间,global 等等
declare class Cust {
  constructor(parameters) {

  }
}

(二十二) mixins

mixins 混入,对象混入,类的混入。合并后其中都包含的属性。

interface Name{
  name:string
}

interface Age{
  age:number
}

interface Sex{
  sex:number
}

let a:Name = {name:'xx'}
let b:Age = {age:33}
let c:Sex = {sex:1}
let obj = Object.assign(a,b,c)   //Name & Age & Sex 混入

class A{
  type:boolean
  changeType(){
    this.type = !this.type
  }
}

class B{
  name:string
  getName():string{
    return this.name
  }
}

// 约束类型  占位符(和继承有区别)
class C implements A,B{
  type:boolean = false
  name:string = '阿飞'
  changeType:()=>void
  getName:()=>string
}

// 手动挂载到原型上
function mixins(curCls:any,itemCls:any[]){
  itemCls.forEach(item=>{
    Object.getOwnPropertyNames(item.prototype).forEach(name=>{
      curCls.prototype[name] = item.prototype[name]
    })
  })
}
mixins(C,[A,B])

let ccc = new C()

console.log(ccc.type);

ccc.changeType()

(二十三)装饰器 Decorator

需要配置tsconfig文件:"experimentalDecorators": true, "emitDecoratorMetadata": true,

就是简化一些操作,对使用装饰器的都执行对应的操作。在不了解其中方法和属性时,不破坏结构,装饰器可以实现。

1.类装饰器  ClassDecorator

// 1.类装饰器  ClassDecorator
// 定义一个方法,指定类型,@+名称 使用 就可以在编译过程中调用
// 执行会回传,target(是类的构造函数,不是原型对象)
const Base:ClassDecorator = (target) => {
  // console.log(target);
  target.prototype.__name = '小'
  target.prototype.fn = ()=>{
    console.log('憨憨');
  }
}

// 好处1:可以在不了解类中方法和属性时,不想破坏其中结构时,装饰器可以添加
// !!! 如果这种方法不支持的话,profill的话, Base(Http) 的调用也是可以的
@Base
class Http{

}

const http = new Http() as any
http.fn()

2.属性装饰器 PropertyDecorator

const Name:PropertyDecorator = (target,key)=>{
  // target原型对象,key 属性名称
  console.log(target,key);
}

// 2.属性装饰器 PropertyDecorator
  @Name
  elname:string

3.参数装饰器 ParameterDecorator

// 通过 reflect-metadata reflect原数据来存储 ,安装一下 npm i reflect-metadata
const Result = ()=>{
  const fn:ParameterDecorator = (target,key,index)=>{
    // target原型对象,key 函数名称,index 参数位置
    // console.log(target,key,index);
    Reflect.defineMetadata('_key','data',target)  // 存储 命名,值,对象
  }
  return fn
}

getList( @Result() data:any){
    console.log(data);
  }

4.方法装饰器 MethodDecorator  PropertyDescriptor

// 4.方法装饰器 MethodDecorator  PropertyDescriptor
// 可以简化请求中的方法,直接输入url,可以返回data
const Get = (url:string)=>{
  const fn:MethodDecorator = (target,key,descriptor:PropertyDescriptor)=>{
    // target原型对象,key方法名称,descriptor描述符
    // console.log(target,key,descriptor);
    const _key = Reflect.getMetadata('_key',target) // 读取  命名,对象
    axios.get(url).then(res=>{
      descriptor.value(_key ? res.data[_key] : res.data)  // 返回到方法里
    })
  }
  return fn
}

 @Get('https://mon.zijieapi.com/monitor_web/settings/browser-settings?bid=2608&store=1')
  getList( @Result() data:any){
    console.log(data);
  }

5.装饰器工厂(函数柯力化)

// 装饰器工厂,函数柯力化
const Base2 = (name:string) => {
  const fn:ClassDecorator = (target)=>{
    target.prototype.__name = name
    target.prototype.fn = ()=>{
      console.log('憨憨');
    }
  }
  return fn
}

6.import 'reflect-metadata',,reflect原数据来存储 ,安装一下 npm i reflect-metadata。

包含以上装饰器的类:

@Base2('yu')
class Http2{

  // 2.属性装饰器 PropertyDecorator
  @Name
  elname:string
  constructor(){
    this.elname = 'weiw'
  }

  // 3.参数装饰器 ParameterDecorator
  @Get('https://mon.zijieapi.com/monitor_web/settings/browser-settings?bid=2608&store=1')
  getList( @Result() data:any){
    console.log(data);
  }

  create(){

  }
}
const http2 = new Http2() as any

(二十四)proxy

proxy代理 13个方法,参数一模一样,拦截器。

reflect 反射 13个方法,参数一模一样。

proxy 支持对象,数组,函数,set,map,引用类型

let personProxy = new Proxy(person,{....})

let personProxy = new Proxy(person,{
  // 取值
  get(){
  },
// 赋值
// target 目标自身,key key值,value 赋值,receiver 为了防止箭头函数的错乱,相当于自身
  set(target,key,value,receiver){
    return true
  },
  // 拦截函数调用
  apply(){
  },
  // 拦截 in 操作符
  has(){
  },
  // 拦截 for ..in.. 操作
  ownKeys(){
  },
  // 拦截 new 操作符
  construct(){
  },
  // 拦截 delete 操作
  deleteProperty(){
  },
  // 拦截 Object.defineProperty
  defineProperty(){},
  // 拦截 Object.getOwnPropertyDescriptor
  getOwnPropertyDescriptor(){},
  // 拦截 Object.preventExtensions
  preventExtensions(){},
  // 拦截 Object.getPrototypeOf(proxy)
  getPrototypeOf(){},
  // 拦截 Object.isExtensible
  isExtensible(){},
  // 拦截 Object.setPrototypeOf
  setPrototypeOf(){},

})

reflect 可以直接操作对象,方法参数一模一样,方便我们的操作。

let personProxy = new Proxy(person,{
  get(target,key,receiver){
    if(target.age <= 19){
      return Reflect.get(target,key,receiver)  // Reflect 可以直接操作对象,方法一模一样
    }else{
      return 'okkk'
    }
  }
})

// console.log(personProxy.age);

实现 mobx 的 observable 观察者模式

// 存储器
const list:Set<Function> = new Set()

// 订阅函数
const autorun = (cb:Function)=>{
  if(!list.has(cb)){
    list.add(cb)
  }
}

// 观察者
const observable = <T extends object>(params:T)=>{
  return new Proxy(params,{
    set(target,key,value,receiver){
      const result = Reflect.set(target,key,value,receiver) // 返回布尔值
      list.forEach(fn => fn())
      return result
    }
  })
}

const ppProxy = observable({name:'hihi',attr:'发将诶啊哦'})

autorun(()=>{
  console.log('有变化了');
})

ppProxy.attr = '基金哦溶解'
ppProxy.name = '接口分'

(二十五)协变

鸭子类型:如果走起路来像鸭子,叫起来也像鸭子,那么它就是鸭子。

一个对象的特征不是由父级决定的,而是通过对象的方法决定的。

协变----子类型如果包含主类型的所有属性,那么可以被赋值。

逆变----通常发生在函数上。(一定是安全的。)

interface A {
  name:string
  age:number
}
interface B {
  name:string
  age:number
  sex:string
}

let a:A = {
  name:'吃鱼了',
  age:34
}
let b:B = {
  name:'高强度',
  age:24,
  sex:'男'
}

// 协变 -- 子类型如果包含主类型的所有属性,那么可以被赋值
a = b

// 逆变 -- 通常发生在函数上
let fna = (p:A)=>{}
let fnb = (p:B)=>{}
// 一定是安全的
fnb = fna

// 如果要实现 双向协变 需要tsconfig中开启 "strictFunctionTypes": false,
fna = fnb

(二十六)weakmap

(如果在 package.json 中加 type:module属性,可以使用 ts-node-esm )

weakmap,weakset 弱引用

和垃圾回收机制有关,不会被计入垃圾回收。weakmap的key只能是引用类型。引用类型释放后,weakmap也会消失。

(有时控制台可以输出,但是取不到值,v8的回收需要时间。200ms,因为不稳定,所以不允许取键值)

// weakmap weakset  弱引用
// 和垃圾回收机制有关, 不会被计入垃圾回收。
// weakmap和map的区别是,weakmap的key只能是引用类型
let obj:any = {name:'呜呜呜'}  // 引用1
let aabb:any = obj  // 引用2
let weakmap:WeakMap<object,any> = new WeakMap()
weakmap.set(obj,'asdf')  // 引用还是2 ,不会计入垃圾回收
// 所以 obj 和 aabb 释放之后,weakmap也会消失。
// 有时控制台可以输出,但是取不到值,v8的回收需要时间。200ms,因为不稳定,所以不允许取键值

// 释放
// obj = null // -1
// aabb = null  // -1
console.log(weakmap.get(obj));

(二十七) Partial

Partial 可选的   

Pick 摘出,筛选

Readonly  只读

Record 同时约束 key,value

type Person = {
  name:string,
  age:number,
  text:string
}

// type Par<T> = {
//   [P in keyof T]?:T[P]
// }

type P1 = Partial<Person>


// type PPP<T,K extends keyof T> = {
//   [P in K]:T[P]
// }

type P2 = Pick<Person,'age'|'name'>


// type R<T> = {
//   readonly [P in keyof T]:T[P]
// }

type P3 = Readonly<Person>

// keyof any 相当于 string | number | symbol

// type Rec<K extends keyof any,T> = {
//   [P in K] : T
// }

type P4 = Record<string,Person>

(二十八)infer

infer 占位符

定义一个类型:如果是数组类型就返回数组类型,否则,传入什么类型,就返回什么类型。

// type TY<T> = T extends Array<any> ? T[number] : T

// 这里infer是一个占位符,读Array的类型,取别名U使用

type TY<T> = T extends Array<infer U> ? U : T

type AA = TY<string[]> // string

type BB = TY<boolean> // boolean

还可以进行更加细致的筛选和占位

type Arr = ["a", "b", "c"]

// type First<T extends any[]> = T extends [infer one,infer two,infer three] ? one :[]
type First<T extends any[]> = T extends [infer one, ...any[]] ? one : [] // 取头部元素
type Last<T extends any[]> = T extends [...any[], infer last] ? last : [] // 取尾部元素
type Pop<T extends any[]> = T extends [...infer Rest, unknown] ? Rest : [] // 取除最后一个的其他元素
type Shif<T extends any[]> = T extends [unknown, ...infer Rest] ? Rest : [] // 取除第一个的其他元素

type aa = First<Arr>
type ll = Last<Arr>
type pp = Pop<Arr>

还可以递归,实现反向数组

// infer 递归
// 实现 反向
type arr = [1, 2, 3, 4]

type ReverArr<T extends any[]> = T extends [infer first, ...infer rest]
	? [...ReverArr<rest>, first]
	: T

type arrb = ReverArr<arr>  // [4,3,2,1]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值