Typescript学习笔记

2023-11-20

Typescript学习笔记

什么是Typescript

​ TypeScript是一种由微软开发的开源、跨平台的编程语言。它是JavaScript的超集,最终会被编译为JavaScript代码;TypeScript适合用来编写基于node的大型应用;ts的静态语言特性,能帮助我们在开发时候就发现自己语法的错误,而非像其他js在运行时才发现;ts的类型定义,让代码更加规范,在调用一些方法和api时,能准确的得到方法参数和返回值提示,减少了以往js需要api文档才能开发的问题;

Typescript 的数据类型

基本数据类型

布尔类型(boolean); 数字类型(number); 字符串类型(string); 数组类型(array); 元组类型(tuple); 枚举类型(enum); 任意值类型(any); null和undefined; void类型; never类型;

常用类型(与java的定义差不多)

  //最常用的类型  
  let bool:boolean = true;  
  let str : String = "字符串";
  let num : number = 1.2;
  //两种数组的定义方式
  let strArr : string[] = ["1","23","123"];
  let numArr : Array<Number> = [1,2,3];

Typescript 的强类型判断非常严格,当试图为上文的 str赋值 数字类型时,会报错,体现了ts的静态语言特性,强类型判断

在这里插入图片描述

//元组(Tuple)可以理解为一个长度,每一项元素类型都确定的数组
let peopleArr: [string, string, number] = ['Dylan', 'male', 23] //数组中元素的类型和长度都是固定的,与定义的类型和长度一样
//混合类型的数组
let arr:(number|string)[] = [12,'aa','a'];//定义数组类型时,使用 | 连接(union type联合类型),这数据可放入多种类型

any类型及其与object的区别

any任意值类型,在强调类型的ts中,ts对象可以让被赋予如何类型,也可以从any中去任意属性和方法(即使不存在的属性和方法)

let testObj : any = {};
testObj=1;
testObj="aaa";
testObj={
    sayHi(){
        console.log("sayHi")
    }
}
console.log(`testObj不存在的属性---${testObj.aa}`)//调用不存在的属性aa,编译不报错,运行也不保存
console.log(`调用不存在的方法开始`)
testObj.sayNo();//不存在的方法
console.log(`调用不存在的方法结束`)
testObj.sayHi();

在这里插入图片描述

如上代码和运行结果可以看到,any修饰的变量,可以接受任意类型,可以调用不存在的属性但是不能调用不存在的方法;如上,调用不存在的方法,编译不报错,但是运行到 “调用不存在的方法开始`”这个log后,程序开始循环无法正常的往下走;any 类似原生的js对象,ts放弃对此类修饰对象的类型判断

any与object的区别,虽然在接受参数上两者都能接收不同类型,但是编译器,object 使用不存在的属性和方法时,object类型编译报错

在这里插入图片描述

any可以以赋值给任意类型(never类型除外),object则不能赋值给任意类型;any对象可以赋值给string,但是object不行

在这里插入图片描述

never any unkown

​ 将三种类型一起讲,是因为 any和unkown顶部类型,never是底端集合

​ any和unkown 是一切类型的超级类型(supertype)任何值都能冠以类型any和unkown

​ never是一个空集合,任何值都不能冠以类型 never;将某个值的类型解析为 never,编辑就会报错;空集合可包含于任何非空集合,因此never 是一切其它非空类型的子集合。这就是为什么 never 被称为底端集合。

包装类型

interface

以IEMP-SXTL-BFF项目代码来演示interface功能

//在src\inits\modelData\index.ts 向外暴露的CommonResultData
/**
 * 服务返回数据通用结构
 */
export interface CommonResultData {
  code: number;
  msg: string;
  data: Record<string, any>[] | null; 
}
let data :CommonResultData = {
    code:1,
    msg:"aaa"
}
//这种定义,要求该类型的实例的对象,必须要有 code msg data属性,以code为列,code可以 = 数字,null,underfined,但是不能没有code属性
//如果偏偏要让 code 可有可无,则可以 code?: number; 使用问号,则属性中没有code,编译也不会报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UNusM0NH-1612158764817)(C:\Users\tttare\AppData\Roaming\Typora\typora-user-images\image-20210104102645724.png)]

interface无法用new 实例化,class可以

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IrDWkKha-1612158764818)(./img\2020-12-31_153131.png)]

如上图,我们在使用interface修饰的类型时,能很清晰的看到这个类型所需要的属性,这也是ts相比传统js的优势,能让我们在没有api文档的情况下,知道使用的类型中的属性,属性类型,方法,方法参数等信息,这也是ts解决的痛点之一;

let comdata : CommonResultData = {
    code:1001,
    msg:"aass",
    data:null
};//给CommonResultData类型赋值时,CommonResultData类型的三个属性,必须全都要定义,不能是underfine,类型也不能不同

interface和java的接口还是很像的,interface能继承interface,interface不能有方法体,不能用private修饰方法

在这里插入图片描述

ts建议给interface的方法确定返回值

class

在IEMP-SXTL-BFF项目中,class修饰的类型承担更大的作用;class中有大量的方法和注解,主要用来编写业务逻辑

//定义一个oprate类
class Oprate{
    public sayHi(){
    	console.log('public say hi')
    }

    private sayHello(){
    	console.log('private say hello')
    }

    public static sayHalo(){
    	console.log('static say halo')
    }
}

在这里插入图片描述

由上图可知,class的实例能使用被public修改的方法,不能使用被private或static修饰的方法;static修改的方法,直接用类型调用

private 和 public都与java的类似,只是static修饰的方法,类的实例不能使用,与java不相同

extends ,implements,多态

interface不能被class继承

在这里插入图片描述

interface能继承interface,interface不能有private修饰方法,不能有方法体;

在这里插入图片描述

class实现interface必须也定义interface属性,实现interface的方法

在这里插入图片描述

class继承class,能使用父class的方法及属性

在这里插入图片描述

ts也有多态,interface接收实现类的实例,class接收子类的实例

在这里插入图片描述

union(并集) 和 intersection(交集)

定义几个class对象 用来测试交集和并集

interface OpInterface {
    data:number;
    sayToday():number;
} 

class Oprate implements OpInterface{
    data:number;
    public sayToday():number{
        return 12;
    }
}

class OprateSon extends Oprate{
    public saySon(){
        console.log("son class")
    }
}

class Dev {
    code:number;
    data:number;
    public saySon(){
        console.log("son class")
    }

    public sayDev(){
        console.log("dev class")
    }
}

class Mix {
    code:number;
    //下面的方法和属性在 生成的并集中也不存在,但是new Mix可以赋值给并集type
    t1 : string='str';
    sayNo(){

    }
}

class And {
    data : number;
    public saySon(){
        console.log("son class")
    }
}

并集,ts以 | 符号表示

//基本数据类型并集
type mixBasic = number|String;
let a2 : mixBasic = 1;
let a3 : mixBasic = 'str';
//包装类型并集
type mix = Dev | OprateSon;
let devObj : mix = new Dev();
let opObj : mix = new OprateSon();

交集,ts以 & 符号表示

//基本数据类型
//mixBasic  = number|String;她与string的交集 便是string
type andBasic = mixBasic&string;
let and1 : andBasic = "aaa";

//包装类型并集
type mixOne = Dev | OprateSon;
type mixTwo = Dev | Oprate;
type and = mixOne & mixTwo;
let obj1 : and = new Dev();
let obj2 : and = new OprateSon();//mixOne 和 mixTwo 的交集应该只有 Dev类型,为啥可以赋值 OprateSon
//因为 OprateSon 继承了 Oprate,所以ts继承的特性也体现出来了 OprateSon&Oprate 产生的交集是 OprateSon

枚举

枚举定义方式

  enum OprateEnum{

   START,END

  }
  console.log("start..."+OprateEnum.START)
  console.log("end..."+OprateEnum.END)

运行结果

在这里插入图片描述

可以看出,ts的枚举和java枚举有很大不同,在我们没有给START,END赋值的情况下,枚举类型默认从0 开始自增赋值

enum OprateEnumTwo{
    START,SECOND=3,THREE,END
}
//将中间值 设为3 看ts为其他值赋值多少
console.log("start..."+OprateEnumTwo.START)
console.log("second..."+OprateEnumTwo.SECOND)
console.log("three..."+OprateEnumTwo.THREE)
console.log("end..."+OprateEnumTwo.END)

运行结果

在这里插入图片描述

可以发现,还是从0开始,但是 因为我们给SECOND赋值了3,SECOND以后的枚举值,以她为起点自增

在这里插入图片描述

枚举类属性不能用数字命名

在这里插入图片描述

与上面的数字值枚举不同,如果你给枚举赋值了字符串,那该枚举属性之后的属性,必须赋值

当我们去掉T3 T4时,查看运行结果

在这里插入图片描述

TS的枚举类型,要特别主要自动赋值,自增这个特点

注解

TS提供的高级工具类

  • type : 用来接收ts的类型,可以接收一个新的类型,也可以其他ts类型建立别名,别名不会新建一个类型,而是创建一个新名字来引用此类型(一个别名能对应多种类型),type 就是用来接收TS类型的
  //代码中临时创建一个新的类型,用type对象接受
  //NewType 是代码中临时定义的对象
  type NewType = {
    code?:number,
    name?:string
  };
  let typeObj : NewType = {
    code:12,
    name:"sdad"
  };
  //为已有类型创建别名
  //NewCommonResultData是CommonResultData别名,实际作用和CommonResultData一样  
  type NewCommonResultData = CommonResultData;
  let newData : NewCommonResultData = {    
    code:10,
    msg:"aass",
    data:null
  };

  // type接收联合类型,对应多种类型
  type DataOrStr = string | CommonResultData;
  let dataOrStr :  DataOrStr = "aaa";
  dataOrStr = {    
    code:10,
    msg:"aass",
    data:null
  };
  • Partial : 产生新的类型给T所有属性加上?,变为可选
type stu = {
    readonly name:string,//只读,定义后此属性不能修改
    sex:string,//属性 ? 代表是否可为underfined,不要? 则接受值时,必须全部使用
    level:number
};
let stuObj : stu = {name:"武汉",sex:"女",level:7};
//newStr 和 stu 互不影响,newStr时基于stu新的类型
type newStr = Partial<stu>;//Partial 产生新的类型给所有属性加上?,变为可选
let student : newStr = {level:1};//编译不报错,name和sex都可以不定义
  • Required : Required 与Partial正好相反,使得所有属性,必须定义
  • Readonly : 给T所有属性都加上readonly 属性,使其定义后无法修改
type readOnlyStu = Readonly<newStr>;
let readOnlyS : readOnlyStu = {name:"不可能变更"};
//readOnlyS.name = "aaa";//ReadOnly产生的type不能被修改
//readOnlyS.level = 2;//所有属性都不能被修改
  • Pick<T,K extends keyof T> : 从T中挑选部分属性生成新的type
type halfStu = Pick<stu,"sex"|"level">;//Pick 从stu中,拿出部分属性,产生一个新的type
let halfStuObj : halfStu = {sex:"nan",level:1};
  • Omit<T,K extends keyof T>: 删除T部分属性,产生一个新的type,与Pick正好相反
  type delStu = Omit<stu,"sex">;//Omit 删除部分属性,产生一个新的type,与Pick正好相反
  //let delStuObj : delStu = {sex:"a"};//sex被删除,编译报错
  • Extract<T, U>:作用是从 T 中提取出 U
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () => void
  • Exclude<T, U>:将 T 中某些属于 U 的类型移除掉。
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number
  • Record<T,K extends keyof T>

Record使用效果如下

    type petsGroup = 'dog' | 'cat' | 'fish';
    interface IPetInfo {
      name:string,
      age:number,
    }
    type pet = Record<petsGroup,IPetInfo>;

    let petObj : pet = {
      dog : {
        name:'dog',
        age:5
      },
      cat : {
        name:'cat',
        age:9
      },
      fish : {
        name:'fish',
        age:2
      }
      
    }

IEMP-SXTL-BFF项目代码解析

项目启动环境

  • 安装nodejs
  • 更新配置npm
  • 项目部分依赖需要python和c++类库,安装python,vs_community安装c++桌面开发工具
  • npm run dev 启动项目开发环境应用

Koa基于nodeJs的Web框架

服务启动入口

src\index.ts 是整个服务器程序的启动入口

const app = await appInit.init();//调用src\app.ts的init方法,主要返回Koa实例
// 获取Koaservice运行端口号
const serverPort = normalizePort(String(commonCfg.bffConfig.port) || '3000');//端口配置于src\config
//nodeJs创建一个服务器的代码
const server = http.createServer(app.callback());
//事件掩饰设置 0 立即执行
server.setTimeout(0);
//绑定服务器端口
server.listen(serverPort);
server.on('error', onError);
server.on('listening', onListening);

koa app设置
export default {
  async init(): Promise<Koa> {
    //定义一个Koa 服务端实例
    const app = new Koa();
    // 全局变量初始化
    globInit();
    // 全局错误信息处理
    app.use(globalError);
    // 全局token校验
    // app.use(checkToken(AuthService.checkToken));
    // spring监控
    app.use(actuator());
    // 重放攻击保护
    // if (commonCfg.env !== 'dev') {
    //   app.use(replayAttack(['swagger', 'actuator', '/system', 'example']));
    // }
    // 日志
    app.use(koaLogger());
    // 请求信息打印
    app.use(requestInfo);
    // 数据压缩
    app.use(
      koaCompress({
        threshold: 2048,
        flush: require('zlib').constants.Z_SYNC_FLUSH,
      }),
    );
    // 格式化返回值
    app.use(resFormatter);
    // 初始化框架
    initFrame(
      app,
      {},
      {
        authorizationChecker,
      },
    );
    // eureka注册
    if (commonCfg.registerToEureka) {
      eureka.start(async () => {
        await initData.init();
      });
    } else {
      await initData.init();
    }
    return app;
  },
};

主要定义了 服务器端实例

const app = new Koa();

app.use(参数:方法):只能用于注册中间件并且必须是生成器函数

app.use(function)
路由设置

src\inits\initFrame.ts中定义了koa-router及其配置,及外部访问程序的设置

const defaultRoutingControllersOptions: RoutingControllersOptions = {
  //controller层包路径,于javacontroller的逻辑一致
  controllers: [`${baseDir}/controllers/**/*{.js,.ts}`],
  //middlewares包路劲,配置了koa-actuator 应该是永濑监控程序运行情况的
  middlewares: [`${baseDir}/middlewares/**/*{.js,.ts}`],
  //url前缀
  routePrefix: '/bff/v1',
  validation: true,
  cors: true,
  defaultErrorHandler: false,
};

// koa app设置路由规则
koa.use(router.routes());
编写对外提供的服务(controller + service)

如上,我们定义了一个web服务器的实例,端口,url前缀,接下来编写程序,为服务提供功能

在controllers包下定义controller类:TttareController
/**
 * @Description:
 * @author: 测试ts编写的controller层
 * @date: 2020/01/02
 */
import { Inject } from 'typedi';
import { Body, Get, JsonController, Param, Post, Put, Authorized, Ctx } from 'routing-controllers';
import { ApiOperation, ApiTag } from '../lib/routing-controllers-openapi';
import CreateUserBody from '../definitions/CreateUserBody';
import { CustomError } from '../common/CustomError';
import UserDataManager from '../biz/example/UserDataManager';


@ApiTag('示例')
@JsonController('/tttare')
export default class TttareController { 
    
  @Inject()
  private userDataInstance: UserDataManager;//ts注入

  @ApiOperation('测试controller的路由和注入', '测试')
  @Get('/noParam')
  getTestData() {
    return this.userDataInstance.getTestData();
  }  

  @Get('/getById/:id')//rest风格 url传参
  getOne(@Param('id') id: number) {
    return { name: `User #${id}` };
  }
  //http://localhost:3001/bff/v1/tttare/getById/12	
  //请求返回
  //{
  //    "name": "User #12"
  //}
	

  @ApiOperation('测试controller的路由和注入,调用参数有返回值', '测试')
  @Post('/param')
  getTestDataWithParam(@Ctx() ctx,//ctx是context的缩写
  @Body()
  queryParam: any) {
    console.log(ctx);
    console.log(queryParam);
    return this.userDataInstance.getTestDataWithParam(queryParamList);
  }  
}

@Ctx() ctx是context的缩写中文一般叫成上下文,这个在所有语言里都有的名词,可以理解为上(request)下(response)沟通的环境,所以koa中把他们两都封装进了ctx对象,koa官方文档里的解释是为了调用方便,ctx.req=ctx.request,ctx.res=ctx.response,类似linux系统中的软连接?最终执行还是request和response对象

// log ctx对象如下
{ request:
   { method: 'POST',
     url: '/bff/v1/tttare/param',
     header:
      { 'content-type': 'application/json',
        'user-agent': 'PostmanRuntime/7.24.0',
        accept: '*/*',
        'cache-control': 'no-cache',
        'postman-token': 'aecaa0bc-108c-4a4e-8535-d36304b21b61',
        host: 'localhost:3001',
        'accept-encoding': 'gzip, deflate, br',
        connection: 'keep-alive',
        'content-length': '35' } },
  response:
   { status: 404,
     message: 'Not Found',
     header: { vary: 'Accept-Encoding, Origin' } },
  app: { subdomainOffset: 2, proxy: false, env: 'dev' },
  originalUrl: '/bff/v1/tttare/param',
  req: '<original node req>',
  res: '<original node res>',
  socket: '<original node socket>' }

@Body() queryParam: any body是请求体,接收请求的json字符串,将json字符串转为js对象

//log queryParam对象如下
[ { 'name ': 'tttare', sex: '男', level: 2 },
  { 'name ': 'tom', sex: '男', level: 3 },
  { 'name ': 'mick', sex: '男', level: 2 },
  { 'name ': 'nancy', sex: '女', level: 2 } ]

项目使用typedi框架实现依赖注入

//controller层引入 Inject依赖注入service
import { Inject } from 'typedi';
@Inject()
private userDataInstance: UserDataManager;//ts注入
/**********************************/
//service使用 Service做控制反转,将UserDataManager实例的产生交个框架
import { Service } from 'typedi';
@Service()
export default class UserDataManager 
编写service,注入controller层调用

src\biz\example\UserDataManager.ts的ts编写逻辑处理

//给学生对象按年级 level 分类 
public getTestDataWithParam(queryParamList: any[]):Map<number,any[]>{
    //ts提供的Map type,和java一样,key-value存储
    let map = new Map<number,any[]>();
    //利用map的api进行学生分组
    queryParamList.forEach(item=>{
      if(map.has(item.level)){
        map.get(item.level).push(item)
      }else{
        map.set(item.level,[item]);
      }
    })
    
    return map;
  }
测试编写的接口

在这里插入图片描述

在这里插入图片描述

断点调试

在vscode界面找到debugger窗口,点击驱动项目

debugger项目启动端口和dev端口一致,要先关了dev环境在这里插入图片描述

debugger启动配置

在这里插入图片描述

debugger过程在这里插入图片描述

开发常见API解析-进阶

异步相关(async await Promise)

​ 异步操作一般是在主线程中,开辟新的线程去做耗时操作,项目中最多的便是网络请求;

  • async 修饰方法,代表此方法方法体内有异步操作,且改方法的返回值会被包装成一个Promise ,默认将方法的返回值作Promise中 resolve方法的参数
  • await 只能存在与被async修饰的方法体内,来修饰一个异步调用操作(或者说修饰一个返回Promise的方法),用来暂停主线程,等待异步调用完成,主线程才开始往下走,感觉是将原先的异步操作,变为了同步一的一种效果,一般是因为主线程下面的操作需要异步调用(网络请求)的返回值;(await 所取的参数来自于Promise中resolve函数的赋值,也就是请求成功时Promise调用的resolve方法)
  • Promise 是为异步编程提供了一种解决方案
名称:Promise,译为“承诺”,这也就表达了将来会执行的操作,代表异步操作;
状态:一共有三种状态,分别为pending(进行中)、fulfilled(已成功)和rejected(已失败)。
特点:(1)只有异步操作可以决定当前处于的状态,并且任何其他操作无法改变这个状态;
	 (2)一旦状态改变,就不会在变。状态改变的过程只可能是:从pending变为fulfilled和从pending变为rejected。如果状态发生上述变化后,此时状态就不会在改变了,这时就称为resolved(已定型)

Promise使用实例

public static testMethod(){
    //Promise 如何实现异步操作
    //将异步操作包装入Promise对象的 (resolve, reject) => {}方法中
    const promise = new Promise((resolve, reject) => {
        let error = '连接失败';
        let value ="请求成功";
        let success = false;
        if (success) {
            resolve(value); //pending => fulfilled
        } else {
            reject(error); // pending => rejected
        }
    });
    //如何获取异步操作的执行结果
    promise.then((v)=>{
        //then 获取到 resolve(value) 方法的参数 value
        console.log(`then:${v}`)
    }).catch((e)=>{
        //catch 获取 reject(error) 方法的参数 error
        console.log(`catch:${e}`)
    }).finally(()=>{
        //finally 必须执行的处理
        console.log("处理结束")
    })
    return promise
}
//调用testMethod方法
@post("/forTest")
async fotTest(ctx){
    console.log("start...")
    AccountService.testMethod();
    console.log("end...")
}

执行结果

在这里插入图片描述

如上图所示,Promise对象已经将我们的操作变为异步操作了

async 标记方法实例

//方法和简单,async能不能让方法异步
public static async testMethod2(){      
    console.log("async方法执行中")
    return "aaa"
}

@post("/forTest")
async fotTest(ctx){
    console.log("start...")
    //async 的返回值只能用Promise对象接收
    let p:Promise<any> = AccountService.testMethod2();
    p.then((v)=>{
        //then中操作方法的返回值
        console.log("取到asyn方法返回值"+v)
    })
    console.log("end...")
}

在这里插入图片描述

如上图所示,async标记的方法,方法体并不是异步的,异步操作需要Promise来实现,new Promise和Promise的then,catch,finally是异步的;故async更多是标记方法存在异步操作,并使得方法的返回值被Promise包装

IBS-BFF项目异步操作实例(async await Promise的组合运用)

//RedisUtil中的hgetall方法,讲操作redis异步进行
async hgetall(key): Promise<any> {
    return new Promise((resolve, reject) => {
        client.hgetall(key, (err, res) => {
            //成功与失败都调用resolve,是为了方便用 await取值
            if (err) {
                resolve(false);
            } else {
                resolve(res);
            }
        });
    });
}

//await 修饰的async方法,会直接拿到方法返回值中的 resolve参数
//await redisUtil.hgetall 可知,data为Promise resolve方法的参数,及默认取调用成功的返回值
const data = await redisUtil.hgetall(this.inSettleAccountKey);
if (data !== false) {
    for (const key in data as any) {
        if (data.hasOwnProperty(key)) {
            if (new Date().getTime() - parseFloat(data[key]) >= this.expiredTime) {
                await this.deleteAccountCalData(parseInt(key), true);
            }
        }
    }
} else {
    G.logger.error('账户缓存数据读取出错');
}

//await Promise.all参数是一个异步方法集合,dataList则为一个数据,
//长度为方法集合长度,dataList的集合对应的是每个异步方法的返回值
//all将多个异步操作放在一起成为一个新的Promise,如果都成功,则返回长度相同的返回值数组
//一旦有一个失败,则返回第一个失败操作的reject状态值,
//有点事务的意思,集合内的异步方法要么都成功,只要有一个失败,则认为他们都失败
const dataList = await Promise.all([
    MeterInfoQuery.queryLineShareSchemeAccountMapData(),
    this.queryLineGatewayMapData(lineIDList),
    MeterInfoQuery.queryLineAccountDataMap(lineIDList),
]);

装饰器和注解

装饰器(Decorator):仅提供定义劫持,能够对类及其方法、方法入参、属性的定义并没有提供任何附加元数据的功能。

注解(Annotation):仅提供附加元数据支持,并不能实现任何操作。需要另外的 Scanner 根据元数据执行相应操作。

TS中,注解和装饰器是可以说是一个东西,缺一不可,注解提供元数据,即其可以通过修饰类和方法、参数上,为装饰器提供元数据(类信息,方法信息,参数,以及注解本身的入参),而装饰器则负责实现对元数据 进行功能的扩展;

@controller('/account')
export default class AccountController extends BaseController {
   ~ ~ ~ ~ ~ ~ ~ ~
}

以TS Web服务开发常用的@controller注解为例子,其定义如下

export declare const controller: (path?: string) => ClassDecorator;

注解将自身的参数 path传递给了ClassDecorator 类装饰器,而类处理器本身是一个Function

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;

typedi框架的AOP和IOC

@Service()
export default class UserDataManager {
    ~~~~~~
}

@JsonController('/users')
export default class UsersController {
 	@Inject()
	private userDataInstance: UserDataManager;   
}

//TODO

常用工具类

  • moment 时间日期操作工具类
import * as moment from 'moment';

const startTime = moment().format('YYYY-MM-DD HH:mm:ss');//2021-01-20 16:42:20  当前时间字符串形式
const endTime = moment()
.add(1, 'd')//'d'  时间单位: 天
.format('YYYY-MM-DD 00:00:00');//2021-01-21 00:00:00   当前时间加一天
//将指定时间戳转成时间字符串
const startTime2 = moment(1609430400000).format('YYYY-MM-DD HH:mm:ss');//2021-01-01 00:00:00
//moment 的时间单位如下
"year" | "years" | "y" |
"month" | "months" | "M" |
"week" | "weeks" | "w" |
"day" | "days" | "d" |
"hour" | "hours" | "h" |
"minute" | "minutes" | "m" |
"second" | "seconds" | "s" |
"millisecond" | "milliseconds" | "ms"
  • lodash( _ ) js常用工具库

lodash工具类对象用 _ 表示,就像jquery 用 $ 一样,全部API文档地址https://www.lodashjs.com/docs
下面为项目中对 lodash 工具类的使用实例

let params = [{
    name : 'aaa',
    age : 12
},{
    name : 'bbb',
    age : 14
} ,{
    name : 'CCC',
    age : 11
},{
    name : 'ddd',
    age : 9
}]
//G._.cloneDeep 深克隆
let newParams = G._.cloneDeep(params);
//G._.get 数组取值,第一个参数为数组,第二个为path集合
//path 第一个值为索引,第二个为属性,类似与面包屑取值,层层向下取值
let getParams = G._.get(params,[1,"name"]);// bbb
//G._.remove 便利数组,将满足条件的元素从数组中移除
G._.remove(params,param =>{
    return param.age > 13
})
//将多维数组 递归为一维数组
let newArray = G._.flattenDeep([1, [2, [3, [4]], 5]]);//[1,2,3,4,5]
//将数组按 size=2分组,无法被分割成全部等长的区块,那么最后剩余的元素将组成一个区块
let chunkArray = G._.chunk(newArray,2);//[[1,2],[3,4],[5]] 
//G._.uniq 数组元素去重
let uniqArr = G._.uniq([1,2,3,3,3,5,5]);//[1,2,3,5]
//对长度小于2的字符串,进行前或后的拼接 0 补位,如果长度大于等于2则不处理
let start = G._.padStart("9", 2, '0');//09
let end = G._.padEnd("9", 2, '0');//90
let end2 = G._.padEnd("19", 2, '0');//19
let initList = [[{text:"卧推"}],[{text:"深蹲"}],[{text:"侧平举"}]];
//将多维数组变成一维数组
let flatMap = G._.flatMapDeep(initList);//[{text:"卧推"},{text:"深蹲"},{text:"侧平举"}]
//连个数组元素取交集
let interArr = G._.intersection([1,2,4,5],[2,3,4]);//[2,4]
//集合对象按属性排序  按age 升序排列
let orderArr = G._.orderBy(newParams, ['age'], ['asc'])
//按字段分组
const groupData = G._.groupBy(data.data, item => {
    return item.operator;
});
return "aaa"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Typescript学习笔记 的相关文章

随机推荐

  • 【uniapp】使用canvas组件编译到微信小程序兼容出错问题

    使用uniapp编译跨平台项目会遇到不少兼容问题 这里主要讲canvas组件的 编译到微信小程序会有兼容出错问题 这里给讲一下解决方案 希望有帮助 常见问题 draw无法绘制图形 如果使用CanvasContext绘制 以下代码 编译到微信
  • 值得收藏的UmiJS 教程

    点击上方关注 前端技术江湖 一起学习 天天进步 前言 网上的umi教程是真的少 很多人都只写了一点点 很多水文 所以打算自己写一篇 自己搭建umi 并封装了一下常用的功能 并用到公司实际项目中 umi介绍 Umi 是什么 Umi 中文可发音
  • maven学习笔记 maven的使用

    新建maven项目 使用mvn archetype generate命令新建一个maven项目 maven会自动下载必要的插件 还会下载一个所有项目模板的分类文件 这个文件有好几兆的大小 因此可能会持续比较长的时间 下载完毕之后 就会列出所
  • JAVA 8 新特性及使用

    1 前言 2019年9月19日java13已正式发布 感叹java社区强大 经久不衰 由于国内偏保守 新东西总要放一放 让其他人踩踩坑 等稳定了才会去用 并且企业目的还是赚钱 更不会因为一个新特性去重构代码 再开发一套程序出来 甚者国内大多
  • 不一样的联宇益通,不一样的SD-WAN+

    点击上方 中国云报 可关注 笔者有点挠头 究竟该用哪个词来描述联宇益通 Netpas 公司呢 低调 技术控 特立独行 还是自得其乐 似乎都有些影子 但又都不是最准确的表达 与联宇益通创始人兼CEO谢毅斌聊得越深入 感觉联宇益通身上矛盾的地方
  • 软件测试 app自动化02 Appium常用的元素定位工具 元素的属性 元素定位方法

    文章目录 1 Appium常用的元素定位工具 1 1 uiautomatorviewer 1 2 Appium Inspector 1 3 Weditor 2 元素的属性 3 元素定位方法 小结 1 Appium常用的元素定位工具 1 1
  • 数据库学习笔记(8)——mysql中的函数和存储过程

    1 MySQL中的函数 1 数据库主要做存储和查询操作 逻辑操作一般不在数据库中进行操作 2 MySQL中的函数主要是自定义函数 其中自定义函数格式如下 修改语句结束符 delimiter create function 函数名 参数名 数
  • 操作系统常见面试题

    1 什么是进程 Process 和线程 Thread 有何区别 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动 进程是系统进行资源分配和调度的一个独立单位 线程是进程的一个实体 是CPU调度和分派的基本单位 它是比进程更小的能
  • java-线程锁

    实现锁 1 同步代码块 2 同步方法 在方法的头部加上synchronized 3 Lock 功能比synchronized更加的强大 但是加锁的时一定不要忘记解锁unlock 在使用lock锁时 想要实现睡眠唤醒功能 就要使用condit
  • 决策报表---动态参数实现多级下拉折叠菜单

    1 描述 在报表开发中 我们会遇到报表需要对行标题实现展开收起的折叠菜单的效果 这种效果一般在分析预览或者填报中应用下拉树控件来实现 但是在分页预览或者决策报表如何实现呢 这里我们使用动态参数的方式 预期效果 1 在分页预览和决策报表中能适
  • 操作系统中的线程&进程和同步&异步和并发&并行

    操作系统中的线程 进程和同步 异步和并发 并行 一 进程和线程 1 1 进程 1 2 线程 1 3 实现多任务的方法 1 3 1 使用多进程实现多任务 1 3 2 使用多线程 单个进程包含多个线程 实现多任务 1 3 3 使用多进程 多进程
  • vue+element中如何设置单个el-date-picker开始时间和结束时间关联

    功能 选了开始时间 则结束时间只能选择开始时间之后的 选了结束时间 则开始时间只能选择结束时间之前的 重点是picker options属性 图示 代码展示 body 内部
  • JavaScript设计模式-02-单例模式

    Javascript 设计模式 02 单例模式 简介 单例就是保证一个类只有一个实例 实现的方法一般是先判断实例是否存在 如果存在直接返回 如果不存在就创建了再返回 确保了一个类只有一个实例对象 在JavaScript里 单例作为一个命名空
  • AIGC(AI Generated Content,人工智能生成内容)

    AIGC AI Generated Content 人工智能生成内容 什么是AIGC AIGC Artificial Intelligence Generated Content AI Generated Content 中文译为人工智能生
  • 读《effective modern c++》笔记总结

    文章目录 一 类型推导与auto 模板类型推导 ParamType是一个指针或引用 但不是通用引用 ParamType是一个通用引用 ParamType即不是指针也不是引用 数组实参 函数实参 auto类型推导 二 decltype的理解
  • make menuconfig报错:Build dependency: Please install Git (git-core) >= 1.6.5

    版本号为chaos calmer 15 05 1 注意 在执行make menuconfig的时候 会报一个错误 如下 Build dependency Please install Git git core gt 1 6 5 这是open
  • 节流与防抖

    1 我们先了解为什么要节流和防抖 我们给一个inpu输入框绑定一个oninput事件 此时我们输入 前端开发 四个字 我们 观察以下后台打印
  • 树莓派视觉小车 -- 小球追踪(颜色追踪)(OpenCV色彩空间HSV)

    目录 效果展示 基础理论 HSV 为什么用HSV空间而不是RGB空间 HSV 1 Hue 色相 2 Value 明度 3 Saturation 饱和度 一 初始化 滑动条初始化 1 创建回调函数 2 窗口设置 名称 3 滑动条设置 代码 二
  • Linux环境安装开发grafana插件(一)试水

    继续我们探索grafana结合Skywalking 为了更加灵活的应用图表 尝试开发grafana的panel插件 但试水并不顺利 所以把第一步目标缩小到安装一个自定义插件 参考了不少文章 终于成功 但各类参考要么比较碎片化 要么有些地方过
  • Typescript学习笔记

    Typescript学习笔记 什么是Typescript TypeScript是一种由微软开发的开源 跨平台的编程语言 它是JavaScript的超集 最终会被编译为JavaScript代码 TypeScript适合用来编写基于node的大