Typescript詳解

大鵬_yp發表於2021-09-15
  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中的型別

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)

六、模組

  • 模組的的概念(官方):
    1. 關於木語的一點說明:請務必注意一點,TypeScript 1.5裡木語名已經發生了變化。“內部模組”現在稱做“名稱空間”。外部模組“現在則簡稱為“模組#模組在且自身的作用域裡執行,而不是在全域性作用域裡:
    2. 這意味著定義在一個模組裡的變數,因數,類等等在模組外部是不可見的,除非你明確地使用export形式之一匯出它們。相反,如果想使用其它模組匯出的變數,國數,類,介面等的時候,你必須要匯入它們,可以使用 import形式之一。
  • 模組的概念(自己理解):
    1. 我們可以把一些公共的功能單獨抽離成一個檔案作為一個模組。
    2. 模組裡面的變數 函式 類等預設是私有的,如果我們要在外部訪問模組裡面的資料(變數、函式、類),我們要要通過export暴露模組裡面的資料(變數、團數、類。。》。
    3. 暴露後我們通過 import 引入模組就可以使用模組裡面暴露的資料(變數、函式、類...)。

自定義模組

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();