Typescript详解
阅读原文时间:2021年09月15日阅读:3
  1. typescript由微软开发的一款开源编程语言。

  2. ts是jacascript的超集,遵循ES6,ES5规范,ts扩展了js的语法。

  3. ts更像后端java,c#这样的面向对象的语言,可以让js开发大型的企业项目,

  4. 谷歌也大力支持ts的推广,谷歌的angular2.x就是基于ts语法开发的

  5. 最新的Vue,React也继承ts

  6. Nodejs框架Nestjs,midway中用的就是ts语法.

    目录

安装:npm i -g typescript

验证是否安装成功:tsc -v

Version 4.4.3

编译ts:tsc index.ts(需要编译的ts文件)

ts开发工具 vscode自动编译ts

  1. 创建tsconfig.json文件

    tsc --init 生成配置文件

    只改tsconfig:outdir:'./js'

  2. 自动生成js

    vscode-->终端-->运行任务-->typescript-->tsc:监视

ts中为了是编写的代码更加规范,更有利于维护,增加了类型校验。

类型赋值错误会报错,

主要类型有:

类型

名称

解释

写法

布尔类型

boolean

true/false

var flag:boolean=true

数值类型

number

整数/小数

var num:number=123

字符串类型

string

字符串

var str:string='123'

数组类型

array

数组

let arr:number[]=[1,2,3](只能放number类型)/let arr:Array=[1,2,3](只能放number类型,泛型定义)/

元组类型

tuple

数组的一种可以指定数组里每项类型

let arr:[string,number,boolean]=['ww',123,true]

枚举类型

enum

enum 枚举名称{标识符[=整形常数]…}

enum Flag{success:1,err:-1},var f:Flag=Flag.err
enum Color={red,blue,orage} ,var c:Color=Color.blue //c==1

任意类型

any

任意的值

let num:any='123'

null、undefined

其他类型子类型

var num:number

void类型

void

没有任何类型,一般用于函数没有返回值

function run():void {}

其他类型

never

包括null,undefined子类型,代表从不会出现的值

never的变量只能被never类型赋值

ES5函数定义

函数声明

function run() {
    return 'run'
}

匿名函数

var run2 = function () { }

ts函数定义方法

1-函数声明

function run1(): string {
    return 'aa'
}

2-匿名函数

var fun2 = function (): number {
    return 123
}

3-传参

function getInfo(name: string, age: number): string {
    return `${name}++${age}`
}
console.log(getInfo('asd', 22))

4-无返回值

```function run3(): void { }````

ts方法的可选参数

ES5方法的实参和形参可以不一样,ts中必须一样,如果不一样需要配置可选参数

注意:可选参数必须配置到参数最后面,用?表示可选

function getInfos(name: string, age?: number): string {
    return `${name}++${age}`
}

默认参数

es5里面没法设置默认参数,es6和ts找那个可以设置默认参数

默认参数可以不传,类似于可选参数

function getInfo1(name: string, age: number = 20): string {
    return `${name}++${age}`
}

剩余参数

1-改进前写法

function sum(a: number, b: number, c: number, d: number): number {
    return a + b + c + d
}

2-改进后

三点运算符 接收新传过来的值

function sum1(...arr: number[]): number {
    var sum = 0
    for (let i = 0; i < arr.length; i++) {
        sum += arr[i]
    }
    return sum
}
alert(sum1(1, 2, 3, 4))

另一种

function sum2(a: number, ...arr: number[]): number {
    var sum = 0
    for (let i = 0; i < arr.length; i++) {
        sum += arr[i]
    }
    return a + sum
}
alert(sum2(1, 2, 3, 4))

函数重载

java中方法的重载,:两个或以上同名函数,但他们参数不一样,这是会出现函数重载情况

ts中的从在,通过为一个函数提供多个函数类型定义来实现多种功能的目的

ts为了箭筒es5和es6从在写法和java中有区别

es5中出现同名方法,下面的会替换上面的方法

ts重载

function getcon(name: string): string;
function getcon(age: number): number;
function getcon(name: string,age: number): string;

function getcon(str: any,age?:number): any {
    if (typeof str == 'string') {
        return '姓名' + str
    } else {
        return '年龄' + str
    }
}

es5继承

  1. es5里面的构造函数

    function Person() {
        this.name = '张珊'
        this.age = 20
        this.run = function () {
        }
    }
  2. 原型链上的属性会被多个实例共享,构造函数不会

    function Person() {
        this.name = '张珊'
        this.age = 20
        this.run = function () {
        }
    }
    Person.prototype.sex = '男'
    Person.prototype.work = function () {
        console.log(this.name)
    }
    Person.getInfo = function () {
        // 静态方法
    }
    var p = new Person()
    p.work()
    // 调用静态方法
    Person.getInfo()
  3. 构造函数与原型链增加方法

    function Person() {
        this.name = '张珊'
        this.age = 20
        this.run = function () {
    }
    } // 原型链上的属性会被多个实例共享,构造函数不会 Person.prototype.sex = '男' Person.prototype.work = function () { console.log(this.name) } Person.getInfo = function () { // 静态方法 } var p = new Person() p.work()
  4. 类里面的静态方法

    function Person() {
        this.name = '张珊'
        this.age = 20
    }
    // 定义静态方法
    Person.getInfo = function () {
    }
    var p = new Person()
    // 调用静态方法
    Person.getInfo()
  5. es5继承

    原型链+对象冒充

    function Person(age) {
        this.name = '张珊'
        this.age = age
    }
    Person.prototype.sex = '男'
    Person.prototype.work = function () {
        console.log(this.name)
    }
    var p = new Person(18)
    // 对象冒充继承---不可以继承原型链的属性和方法
    function Web(){
        Person.call(this)
    }
    
    // 原型链继承-----实例化后没法给父类传参
    Web.prototype=new Person()
    var son=new Web()

ts继承

1、ts定义类

class Person {
    name: string; //属性 省略了public关键词
    constructor(n: string) {
        this.name = n
    }//构造函数,实例化类的时候触发的方法
    run(): void { }
}
var p = new Person('aa')
p.run()

2、ts中实现继承

关键字:extends,super

子类与父类有相同方法,子类优先级更高

class Person1 {
    name: string; //属性 省略了public关键词
    constructor(n: string) {
        this.name = n
    }//构造函数,实例化类的时候触发的方法
    run(): string {
        return `${this.name}是`
    }
}
class Webs extends Person1 {
    constructor(name: string) {
        super(name)//类似于初始化父类构造函数
    }
    work() { }
}
var w = new Webs('李四')

3、ts类里面的修饰符

ts里面定义属性的时候给我们提供了三种修饰符

  • public :公有:在类里面,子类,类外面都可以访问

  • protected :保护类型:在类里面,子类都可以访问,类外面不可以访问

  • private:私有:在类里面可以访问,子类,类外面都不可以访问

  • 属性不加修饰符默认公有public

    class Person2 {
    name: string; //属性 省略了public关键词
    private age: number
    constructor(n: string, a: number) {
    this.name = n
    this.age = a
    }//构造函数,实例化类的时候触发的方法
    run(): string {
    return ${this.name}是
    }
    }

4、静态属性 静态方法

es5里面的

function Person(){}
Person.run2=function(){}//静态方法

ts里面的

静态方法无法调用类里面的属性,可以调用静态属性

class Person3 {
    static sex = 'nam'//静态属性
    public name: string
    constructor(name: string) {
        this.name = name
    }
    run() { }
    static prient() {console.log(this.sex,Person3.sex) }//静态方法
}
var p = new Person3('11')
Person3.prient()//静态方法调用

5、多态

父类定义一个方法不去实现,让继承它的子类去实现,每个子类有不同的表现

多态属于继承的一种表现

class Animal{
    name:string
    constructor(name:string){
        this.name=name
    }
    eat(){
        console.log('吃的方法')
    }
}
class Dog extends Animal{
    constructor(name:string){
        super(name)
    }
    eat(){
        return this.name+'吃肉'
    }
}
class Cat extends Animal{
    constructor(name:string){
        super(name)
    }
    eat(){
        return this.name+'吃鱼'
    }
}

6、抽象方法

  • ts中的抽象类,他提供其他类集成的基类,不能直接被实例化
  • 用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
  • abstract抽象方法只能放在抽象类里面
  • 抽象类的子类必须事项抽象类里面的方法

抽象类和抽象方法用来定义标准

标准:Animal这个类要求他的子类必须包含eat

abstract class Animals{
    /**
     * name
     */
    public name:string
    constructor(name:string){
        this.name=name
    }
    abstract eat():any;
}
// 抽象类的子类必须事项抽象类里面的方法
class Dogs extends Animal{
    constructor(name:string){
        super(name)
    }
    eat(){
        return this.name+'吃肉'
    }
}

接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,换口起到一种限制和规范的作用。接口定义了某一批央所雷要遵守的现范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性面数、可索引和类

1.属性接口

1、对json的约束

ts自定义方法传入对json进行约束

function prientLabel(labelInfo: { label: string }): void {

}
prientLabel({ name: 'aa' })//错误写法
prientLabel({ label: 'aa' })//正确写法

2、对批量方法进行约束

接口:行为和动作规范,对批量方法进行约束

参数顺序可以不一样,但必须得有

关键词:interface

interface FullName {
    firstName: string;//注意;结束
    secondName: string;
}
function prientName(name: FullName) {
    // 必须传入对象 firstName secoendName
    console.log(name.firstName, name.secondName)
}
var obj = { firstName: '1', secondName: 'jj', age: 1 }
prientName(obj)
prientName({ firstName: '1', secondName: 'jj', age: 1 })//传age有问题

接口:可选属性

interface FullNames {
    firstName: string;//注意;结束
    secondName?: string;
}

案例

interface Config {
    type: string;
    url: string;
    data?: string
    dataType: string
}
function ajax(config: Config) {
    var xhr = new XMLHttpRequest()
    xhr.open(config.type, config.url, true)
    xhr.send(config.data)
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
            if (config.dataType == 'json') {
                JSON.parse(xhr.response)
            }
        }
    }
}
ajax({
    type: 'get',
    url: 'http://..',
    data: '',
    dataType: 'json'
})

2.函数类型接口

对传入的参数以及返回值进行约束

加密函数类型接口

interface encrypt {
    (ke: string, value: string): string
}
var md5: encrypt = function (key: string, value: string): string {
    return key + value
}

3.可索引接口

数组,对象的约束(不常用)

interface UserArr {
    [index: number]: string
}
var arr: UserArr = ['11', '22']
interface UserObj {
    [index: string]: string
}
var objw: UserObj = { name: '20' }

4.类类型接口

对类进行约束和抽象类有点相似

关键字:implements

interface Animal1 {
    name: string;
    eat(str: string): void
}
class Dog implements Animal1 {
    name: string;
    constructor(name: string) {
        this.name = name
    }
    eat() {
    }
}

5.接口扩展

接口可以继承接口

interface Animalss {
    eat(): void
}
interface Person extends Animalss {
    work(): void
}
class Son implements Person {
    name: string
    constructor(name: string) {
        this.name = name
    }
    eat() { }
    work() { }
}

class Progeammer {
    name: string
    constructor(name: string) {
        this.name = name
    }
    coding() { }
}
class web extends Progeammer implements Person {
    constructor(name: string) {
        super(name)
    }
    eat() { }
    work() { }
    coding() { }
}
  • 泛型,软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

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

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

    普通写法

    只能返回string类型的数据

    function getData(value:string):string{return value}

返回多种类型的数据 any可以解决这种问题(any放弃了类型检查)

function getData1(value:any):any{return value}

1.泛型定义

  1. 传入和返回类型相同

  2. 可以支持不特定的数据类型

  3. T表示泛型,具体什么类型是调用这个方法的时候决定的

    function getData2<T>(value:T):T{return value}
    getData2<number>(123)
    // getData2<number>(‘kkk’)/* 错误写法 */

2.泛型类

普通写法

class Minclass{
    public list:number[]=[]
    add(num:number){
        this.list.push(num)
    }
    min():number{
        var min=this.list[0]
        for (let i = 0; i < this.list.length; i++) {
           if(min>this.list[i]){
               min=this.list[i]
           }

        }
        return min
    }
}

泛型类写法

class Minclass1<T>{
    public list:T[]=[]
    add(num:T):void{
        this.list.push(num)
    }
    min():T{
        var min=this.list[0]
        for (let i = 0; i < this.list.length; i++) {
           if(min>this.list[i]){
               min=this.list[i]
           }

        }
        return min
    }
}
var m1=new Minclass1<number>()

3.泛型接口

interface ConfigFn{
    (value:string,value2:string):string
}
var setData:ConfigFn=function(val:string,val2:string):string{
    return val+val2
}


interface ConfigFn1{
    <T>(value:T,value2:T):T
}
var setData1:ConfigFn1=function<T>(val:T,val2:T):T{
    return val
}
setData1<string>('123','11')


interface ConfigFn2<T>{
    (value:T):T
}
function getData6<T>(val:T):T{
    return val
}
var myGetData:ConfigFn2<string>=getData6
myGetData('ll')

案例

class User{
    name:string|undefined;
    pass:string|undefined
}
class Mysql{
    add(user:User):boolean{
        return true
    }
}
var u=new User()
u.name='zhang'
u.pass='123'

var db=new Mysql()
db.add(u)

泛型封装

class User1{
    name:string|undefined;
    pass:string|undefined
}
class Mysql1<T>{
    add(info:T):boolean{
        return true
    }
}
var u=new User1()
u.name='zhang'
u.pass='123'
var db1=new Mysql1<User1>()
db1.add(u)

案例

功能:定义一个操作数据库的库支持 Mysql MssqlMongoDb

要求1:Mysql MsSqlMongoDb功能一样都有 add update delete get方法

注意:约束统一的规范、以及代码重用

解决方案:需要约束规范所以要定义接口,需要代码重用所以用到泛型

1、接口:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范

2、泛型 通俗理解:泛型就是解决类 接口 方法的复用性、

interface DBI<T>{
    add(info:T):boolean;
    update(info:T,id:number):boolean
    delete(id:number):boolean
    get(id:number):any[]
}
// 定义一个操作mysql数据库的类
class MysqlDb<T> implements DBI<T>{
    add(info: any): boolean {
        throw new Error("Method not implemented.")
    }
    update(info: any, id: number): boolean {
        throw new Error("Method not implemented.")
    }
    delete(id: number): boolean {
        throw new Error("Method not implemented.")
    }
    get(id: number): any[] {
        throw new Error("Method not implemented.")
    }
}
// 操作用户表  定义一个User类和数据库映射表
class Users{
    name:string|undefined
    pass:string|undefined
}
var u=new Users()
u.name='00'
u.pass='ii'
var omysql=new MysqlDb<Users>()
omysql.add(u)
  • 模块的的概念(官方):

  • 模块的概念(自己理解):

自定义模块

var dburl='xxx'
export function getData():any[]{
    return[{
        title:'123'
    },{
        title:'456'
    }]
}

导入

import {getData} from './db'
getData()

export default 默认导出

每个模块都可以有一个default导出,默认导出使用default关键字标记;并且一个模块只能够有一个default导出,需要使用一个特殊的导入形式

  • 在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内
  • 同Java的包、.Net的命名空间一样,TypeScript的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。命名空间内的对象通过export关键字对外暴露。

命名空间和模块的区别

  • 命名空间:内部模块,主要用于组织代码,避免命名冲突。

  • 模 块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间。

    namespace A{
    interface Animal {
    name: string;
    eat(): void;
    }
    export class Dog implements Animal {
    name: string;
    constructor(theName: string) {
    this.name = theName;
    }

        eat() {
            console.log(`${this.name} 在吃狗粮。`);
        }
    }
    
    export class Cat implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }
    eat() {
        console.log(`${this.name} 吃猫粮。`);
    }
    }

    }

    namespace B{
    interface Animal {
    name: string;
    eat(): void;
    }
    export class Dog implements Animal {
    name: string;
    constructor(theName: string) {
    this.name = theName;
    }

        eat() {
            console.log(`${this.name} 在吃狗粮。`);
        }
    }
    
    export class Cat implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }
    eat() {
        console.log(`${this.name} 在吃猫粮。`);
    }
    }

    }

    var c=new B.Cat('小花');

    c.eat();

封装:模块化+命名空间

export namespace A{
    interface Animal {
        name: string;
        eat(): void;
    }
    export class Dog implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }

        eat() {
            console.log(`${this.name} 在吃狗粮。`);
        }
    }

    export class Cat implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }

        eat() {
            console.log(`${this.name} 吃猫粮。`);
        }
    }   

}


import {A} from './modules/animal';
var d=new A.Dog('小黑');
d.eat();

属性装饰器

装饰器工厂

装饰器定义

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

类装饰器

类装饰器:类装饰器在类声明之前被声明(紧靠着类声明)。 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。 传入一个参数

类装饰器:普通装饰器(无法传参)

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);
http.run();

类装饰器:装饰器工厂(可传参)

function logClass(params:string){
    return function(target:any){
        console.log(target);
        console.log(params);
        target.prototype.apiUrl=params;
    }
}

@logClass('http://www.itying.com/api')
class HttpClient{
    constructor(){
    }

    getData(){

    }
}

var http:any=new HttpClient();
console.log(http.apiUrl);

类装饰器案例

下面是一个重载构造函数的例子。

装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。

如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。

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

@logClass
class HttpClient{
    public apiUrl:string | undefined;
    constructor(){
        this.apiUrl='我是构造函数里面的apiUrl';
    }
    getData(){
        console.log(this.apiUrl);
    }
}

var http=new HttpClient();
http.getData();

属性装饰器

属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。

类装饰器

function logClass(params:string){
    return function(target:any){
        // console.log(target);
        // console.log(params);       

    }
}

属性装饰器

function logProperty(params:any){
    return function(target:any,attr:any){
        console.log(target);
        console.log(attr);
        target[attr]=params;
    }
}
@logClass('xxxx')
class HttpClient{
    @logProperty('http://itying.com')
    public url:any |undefined;
    constructor(){
    }
    getData(){
        console.log(this.url);
    }
}
var http=new HttpClient();
http.getData();

方法装饰器

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

方法装饰会在运行时传入下列3个参数:

2. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

2. 成员的名字。

3. 成员的属性描述符。

方法装饰器一

function get(params:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target);
        console.log(methodName);
        console.log(desc);
        target.apiUrl='xxxx';
        target.run=function(){
            console.log('run');
        }
    }
}

class HttpClient{
    public url:any |undefined;
    constructor(){
    }
    @get('http://www.itying,com')
    getData(){
        console.log(this.url);
    }
}

var http:any=new HttpClient();
console.log(http.apiUrl);
http.run();

方法装饰器二

function get(params:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target);
        console.log(methodName);
        console.log(desc.value);       

        //修改装饰器的方法  把装饰器方法里面传入的所有参数改为string类型

        //1、保存当前的方法

        var oMethod=desc.value;
        desc.value=function(...args:any[]){
            args=args.map((value)=>{
                return String(value);
            })
            oMethod.apply(this,args);
        }

    }
}

class HttpClient{
    public url:any |undefined;
    constructor(){
    }
    @get('http://www.itying,com')
    getData(...args:any[]){
        console.log(args);
        console.log('我是getData里面的方法');
    }
}

var http=new HttpClient();
http.getData(123,'xxx');

方法参数装饰器

参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据 ,传入下列3个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

  2. 方法的名字。

  3. 参数在函数参数列表中的索引。

    function logParams(params:any){

    return function(target:any,methodName:any,paramsIndex:any){
    console.log(params);
    
    console.log(target);
    
    console.log(methodName);
    
    console.log(paramsIndex);
    
    target.apiUrl=params;
    }

    }

    class HttpClient{
    public url:any |undefined;
    constructor(){
    }
    getData(@logParams('xxxxx') uuid:any){
    console.log(uuid);
    }
    }

    var http:any = new HttpClient();
    http.getData(123456);
    console.log( http.apiUrl);

装饰器执行顺序

属性》方法》方法参数》类

如果有多个同样的装饰器,它会先执行后面的

function logClass1(params:string){
    return function(target:any){
      console.log('类装饰器1')
    }
}

function logClass2(params:string){
    return function(target:any){
      console.log('类装饰器2')
    }
}

function logAttribute1(params?:string){
    return function(target:any,attrName:any){
      console.log('属性装饰器1')
    }
}

function logAttribute2(params?:string){
    return function(target:any,attrName:any){
      console.log('属性装饰器2')
    }
}

function logMethod1(params?:string){
    return function(target:any,attrName:any,desc:any){
      console.log('方法装饰器1')
    }
}
function logMethod2(params?:string){
    return function(target:any,attrName:any,desc:any){
      console.log('方法装饰器2')
    }
}

function logParams1(params?:string){
    return function(target:any,attrName:any,desc:any){
      console.log('方法参数装饰器1')
    }
}

function logParams2(params?:string){
    return function(target:any,attrName:any,desc:any){
      console.log('方法参数装饰器2')
    }
}

@logClass1('http://www.itying.com/api')
@logClass2('xxxx')
class HttpClient{
    @logAttribute1()
    @logAttribute2()
    public apiUrl:string | undefined;
    constructor(){
    }

    @logMethod1()
    @logMethod2()
    getData(){
        return true;
    }

    setData(@logParams1() attr1:any,@logParams2() attr2:any,){

    }
}

var http:any=new HttpClient();