TypeScript總結(jié)

TypeScript筆記。一些特性總結(jié)

新的數(shù)據(jù)類型

元祖(Tuple)

屬于數(shù)組的一種,數(shù)組合并了相同類型,元祖合并了不同類型

let tom: [string, number] = ['tom', 25]

枚舉類型(enum)

將一些事物的狀態(tài)和數(shù)值對(duì)應(yīng)起來(lái),盡量用自然語(yǔ)言中的含義清楚的單詞來(lái)表示它的每一個(gè)值。

enum 枚舉名 {
    標(biāo)識(shí)符[=整形常數(shù)]
  標(biāo)識(shí)符[=整形常數(shù)]
  標(biāo)識(shí)符[=整形常數(shù)]
}

enum Flag {
  success = 1,
  error = 2
}

let s:Flag = Flag.success
console.log(s) // 1

enum Flag {
  success ,
  error 
} // 如果標(biāo)識(shí)符沒(méi)有對(duì)映數(shù)值,這位下標(biāo)值

enum Color { // 用具體單詞表示表示數(shù)字狀態(tài)的字符串
    blue,
    red = 3,
    'orange'
}
console.log(Color['red'])//3
console.log(Color.orange) //4
consoloe.log(Color[0]) //blue 枚舉值到枚舉名也會(huì)進(jìn)行反向映射

應(yīng)用,比如說(shuō)錯(cuò)誤的HTTP狀態(tài)碼

任意類型(any)

void類型

void表示沒(méi)有任何類型,一般將用于定義方式的時(shí)候沒(méi)有返回值

never類型

基本上用不到

函數(shù)重載

  • java中方法的重載,指的是兩個(gè)或者兩個(gè)以上同名函數(shù),但它們的參數(shù)不一樣,這時(shí)會(huì)出現(xiàn)函數(shù)重載的情況。

  • typescript中的重載,通過(guò)為同一個(gè)函數(shù)提供多個(gè)函數(shù)類型定義來(lái)試下多種功能的母的。

    ES5不支持后寫的同名函數(shù)會(huì)覆蓋,TS支持

    function reverse(x: number): number;
    function reverse(x: string): string;
    function reverse(x: number | string): number | string {
        if (typeof x === 'number') {
            return Number(x.toString().split('').reverse().join(''));
        } else if (typeof x === 'string') {
            return x.split('').reverse().join('');
        }
    }
    

    重復(fù)定義了多次函數(shù),前面兩次都是定義,string返回string,number返回number;

    最后一次是函數(shù)實(shí)現(xiàn)。

typescript類

實(shí)例修飾符

TS可以使用三種修飾符(modifiers)public,private,protected,修飾實(shí)例屬性可用范圍。

  • public修飾的屬性或方法是公有的,可以在任何地方被訪問(wèn)到,默認(rèn)都是public,在類里面,之類,類外部都可以訪問(wèn)
  • protected修飾的屬性或方法是受保護(hù)的,在類里面、子類里面可以訪問(wèn),在類外部沒(méi)法訪問(wèn)
  • private修飾的屬性或方法是私有的,只能在當(dāng)前類使用。

靜態(tài)屬性 靜態(tài)方法

staticES6 ,靜態(tài)只能調(diào)用靜態(tài)

多態(tài)

  • 父類定義一個(gè)方法不去實(shí)現(xiàn),讓繼承它的子類去實(shí)現(xiàn),每一個(gè)子類有不同的表現(xiàn)。
  • 多態(tài)屬于繼承
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 + '吃老鼠'
  }
}

抽象類

  1. typescript中的抽象類,它是提供其他類繼承的基類,不能被實(shí)例化。

  2. abstract關(guān)鍵字定義抽象和抽象方法,抽象類中的抽象方法不包含具體實(shí)現(xiàn)并且必須在派生類中實(shí)現(xiàn)

  3. abstract抽象方法只能放在抽象類里面

  4. 抽象類和抽象方法用來(lái)定義標(biāo)準(zhǔn)

  5. 抽象類的子類必須實(shí)現(xiàn)抽象類里面的抽象方法

abstract class Animal {
  public name;
  public constructor(name) {
    this.name = name
  }
  abstract sayHi() 
}

class Cat extends Animal {
  public sayHi() {
    console.log(`Tom, My name is ${this.name}`)
  }
}

let car = new Cat('Tom')

interface接口

在面向?qū)ο蟮木幊陶Z(yǔ)言中,接口是一種規(guī)范的定義,它定義里行為和動(dòng)作規(guī)范,在程序設(shè)計(jì)里面,接口起到一種限制和規(guī)范的作用,接口定義了某一批類所需要遵守的規(guī)范。它是對(duì)行為的抽象,而具體如何行動(dòng)需要由類去實(shí)現(xiàn)。

TypeScript中的接口可以用于

  • 對(duì)類的一部分行為進(jìn)行抽象
  • 對(duì)對(duì)象的形狀進(jìn)行描述

屬性類接口

interface Fullname {
  firstName:string;
  secondName:string;
}
function printName(name:Fullname){
  console.log(name.firstname + '-' + name.secondName)
}
//1. 外部包含接口就可以
const obj = {
  age:20,
  firstName: 'Tommy',
  secondName: 'Shen',
}
printName(obj)
//2.嚴(yán)格遵守接口
printName({
  firstName: 'Tommy',
  secondeName: 'Shen'
})
//3.接口可一批量對(duì)映多個(gè)函數(shù)

可選屬性

interface Fullname {
  firstName:string;
  secondName?:string;
}

例子

interface Config {
    method:string;
    url:string;
    data?:string;
    headers?: any;
    dataType:string;
}

function ajax<T>(config:Config):Promise<T> {
    return new Promise((resolve, reject) => {
        let request = new XMLHttpRequest()
        request.open(config.method, config.url, true)
        for(let key in config.headers){
            let value = Headers[key]
            request.setRequestHeader(key, value)
        }
        request.onreadystatechange = () =>  {
            if(request.readyState === 4){
                if(request.status >= 200 && request.status < 300){
          if(config.dataType === 'JSON') {
            resolvs.call(undefined, JSON.parse(request.responseText))
          }else{
            resolve.call(undefined, request.responseText)
          }
                }else if(request.status >= 400) {
                    reject.call(undefined, request.responseText)
                }
            }
        }
    })
}

可索引接口:數(shù)組 對(duì)象的約束

//對(duì)數(shù)組的約束
interface UserArr {
  [index:number]:string
}
//對(duì)象的約束
interface userObj {
    [index:string]:string
}
//類類型的接口 和 抽象類有點(diǎn)相似
interface Animal {
  name:string;
  eat(str:string):void
}

class Dog implement Animal {
  name:string;
  constructor(name:string){
    this.name = name
  }
  eat(){
    console.log(this.name + '吃肉肉')
  }
}

const d = new Dog('小黑')

接口擴(kuò)展:接口可以繼承接口

interface Animal {
  eat():void;
}
interface Person extends Animal{
    work():void
}
class Web implements Person {
  public name:string;
  constructor(name:string){
        this.name = name
  }
  eat(){
    console.log(this.name + '吃噠面王')
  }
  work(){
    console.log(this.name + '寫代碼')
  }
}

類與接口(為什么有了抽象類還需要接口)

implement是面向?qū)ο笾械囊粋€(gè)重要概念,一個(gè)類只能繼承自另一個(gè)類;但不同類之間有一些共有的特性,這時(shí)候就可以把特性提取成接口,一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,大大提高了面向?qū)ο蟮撵`活性。

接口繼承類 (重要 TS特有!?。。?/h5>

常見(jiàn)的面向?qū)ο笳Z(yǔ)言中,接口是不能繼承類的,但是在TS中卻是可以的

class Point {
    x: number;
    y: number;
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
}

interface Pointed3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};

為什么TypeScript會(huì)支持接口繼承類呢?

實(shí)際上,在生命class Point時(shí),除了會(huì)創(chuàng)建一個(gè)名為Point的類之外,同時(shí)也創(chuàng)建了一個(gè)名為Point的類型

class Point {
    x: number;
    y: number;
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
}

interface PointInstanceType {
    x: number;
    y: number;
}

// 等價(jià)于 interface Point3d extends PointInstanceType
interface Point3d extends Point {
    z: number;
}

所以「接口繼承類」和「接口繼承接口」沒(méi)有本質(zhì)的區(qū)別

值得注意的是,PointInstanceType 相比于 Point,缺少了 constructor 方法,這是因?yàn)槁暶?Point 類時(shí)創(chuàng)建的 Point 類型是不包含構(gòu)造函數(shù)的。另外,除了構(gòu)造函數(shù)是不包含的,靜態(tài)屬性或靜態(tài)方法也是不包含的(實(shí)例的類型當(dāng)然不應(yīng)該包括構(gòu)造函數(shù)、靜態(tài)屬性或靜態(tài)方法)。

總結(jié): 聲明Point類時(shí)創(chuàng)建的Point類型只包含其中的實(shí)例屬性和實(shí)例方法

同樣的,在接口繼承類的時(shí)候,也只會(huì)繼承它的實(shí)例屬性和實(shí)例方法。

泛型

泛型: 軟件工程中,我們不僅要?jiǎng)?chuàng)建一致的定義良好的API,同時(shí)也要考慮可重用性。組件不僅能夠支持當(dāng)前的數(shù)據(jù)類型,同時(shí)也能支持未來(lái)的數(shù)據(jù)類型

通俗理解:泛型就是解決 類 接口 方法的復(fù)用性、以及對(duì)不特定數(shù)據(jù)類型的支持

//泛型:可以支持不特定的數(shù)據(jù)類型
//要求:傳入的參數(shù)和返回的參數(shù)一致
//T表示泛型,具體什么類型是調(diào)用這個(gè)方法的時(shí)候決定的
function getData<T>(value:T):T {
    return value
}

//都是any 失去了類型檢查的意義
function createArray(length: number, value: any): Array<any> {
    let result = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray(3, 'x'); // ['x', 'x', 'x']

//使用泛型,調(diào)用的時(shí)候傳入數(shù)據(jù)類型
function createArray<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray<string>(3, 'x'); // ['x', 'x', 'x']

多個(gè)類型參數(shù)

//定義泛型的時(shí)候,可以一次定義多個(gè)類型參數(shù)
function swap<T, U>(tuple: [T, U]):[U, T]{
  return [tuple[1], tuple[0]];
}

swap([7, 'seven']); // ['seven', 7]

交換輸入的元祖

泛型約束

在函數(shù)內(nèi)部使用泛型變量的時(shí)候,由于事先不知道它是哪種類型,所以不能隨意操作它的屬性和方法;這時(shí)可以對(duì)泛型進(jìn)行約束。

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

使用extends約束了泛型T必須符合接口Lengthwise,也就是必須包含length屬性。

泛型接口

//1.
interface ConfigFn{
  <T>(value:T):T;
}
//2.
interface ConfigFn<T>{
  (value:T):T;
}

const getData:ConfigFn = function<T>(value:T):T{
  return value
}
getData<string>('hahaha')

泛型類

與泛型接口類似,泛型也可以用于類的類型定義中

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

泛型參數(shù)的默認(rèn)類型

//當(dāng)使用泛型時(shí)沒(méi)有在代碼中直接指定類型參數(shù)
//TS也無(wú)法推倒出來(lái)類型時(shí),這個(gè)默認(rèn)值就會(huì)起作用
function createArray<T = string>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

命名空間

命名空間和模塊的區(qū)別:

  1. 命名空間:內(nèi)部模塊,主要用于組織代碼,避免命名沖突
  2. 模塊:TS的外部模塊簡(jiǎn)稱,側(cè)重代碼的復(fù)用,一個(gè)模塊里可能會(huì)有多個(gè)命名空間。
namespace A {
    interface Animal {
    name:string;
    eat(str:string):void
    }
    export class Dog implement Animal {
    name:string;
    constructor(name:string){
    this.name = name
    }
         eat(){
        console.log(this.name + '吃肉肉')
    }
}

const d = new A.Dog('小黑')
d.eat()

裝飾器(Class Decorator)

能夠幫助我們來(lái)注釋或者是修改代碼的行為-這鐘做法我們通常稱為元編程。

裝飾器能夠很好的抽象代碼,它們最合適用來(lái)包裝可能會(huì)多處復(fù)用的邏輯

裝飾器工廠可以傳參

裝飾器工廠模式。我們將裝飾器本身封裝在另外一個(gè)函數(shù)中,這樣就能給裝飾器傳遞變量了,例如 @Cool('stuff')。而當(dāng)你不想給裝飾器傳參,把外層那個(gè)函數(shù)去掉就好了 @Cool。

function logClass(params:string){ // 裝飾器工廠
  return function(target:any){ //裝飾器
    console.log(target)
    console.log(params)
    target.prototype.apiUrl = params
  }
}
@logClass('hello')
class HttpClient{
  constructor(){
    
  }
  getData(){
    
  }
}

裝飾器的重載類(構(gòu)造函數(shù)、方法)

類裝飾器使得開(kāi)發(fā)者能夠攔截類的構(gòu)造方法

function logClass(target:any){
  console.log(target)
  return class extends target{
    apiUrl:any = '我是修改后的數(shù)據(jù)'
    
    getData(){
      this.apiUrl + '-----'
      console.log(this.apiUrl)
    }
  }
}

@logClass
class HttpClient{
  public apiUrl: string | undfined;
  constructor(){
    this.apiUrl = '我是構(gòu)造函數(shù)的apiUrl'
  }
  getData(){
    console.log(this.apiUrl)
  }
}

屬性裝飾器

屬性裝飾器表達(dá)式會(huì)在運(yùn)行時(shí)當(dāng)作函數(shù)被調(diào)用,轉(zhuǎn)入下列2個(gè)參數(shù);

  1. 原型對(duì)象
  2. 當(dāng)前屬性的名稱
function logProperty(params:any){
  return function(target:any, propname: any){//1.原型對(duì)象 2.當(dāng)前屬性的名稱
    console.log(target)
    console.log(propname)
    target[propname] = params
  }
}
function logClass(params:string){
  return function(target:any){
    console.log(target)
    console.log(params)
    target.prototype.apiUrl = params
  }
}
@logClass(‘xxxx’)
class HttpClient{
  @logProperty('http://hahaha')
  public Url: any | undfined;
  constructor(){
    this.apiUrl = '我是構(gòu)造函數(shù)的apiUrl'
  }
  getData(){
    console.log(this.Url)
  }
}

// 屬性裝飾器就可以使得我們?cè)趯?duì)屬性賦值之前或在取屬性之后附加一些操作,就像中間件那樣
export class IceCreamComponent {
  @Emoji()
  flavor = 'vanilla'
}

function Emoji(target: Object, key: string | symbol) {
  let value = target[key];
  const getter = () => {
    return value;
  }
    const setter = (next) => {
    console.log('改變')
    value = next
  }
  Object.defineProperty(target, key , {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true,
  })
}

方法裝飾器

它會(huì)被應(yīng)用到方法的 屬性描述符上,可以用來(lái)監(jiān)視,修改或者替換方法定義。

方法裝飾器會(huì)在運(yùn)行時(shí)傳入下列3個(gè)參數(shù)

  1. 對(duì)于靜態(tài)成員來(lái)說(shuō)是類的構(gòu)造函數(shù),對(duì)于實(shí)例成員是類的原型對(duì)象。
  2. 成員的名字
  3. 成員的屬性描述對(duì)象(6個(gè))
function (params:any) {
  return function(target:any, methodsName:string, desc:any){
    //修改裝飾器方法,把裝飾器方法里面?zhèn)魅氲乃袇?shù)改為string類型
    //1.保存當(dāng)前的方法
    const oldMethod = 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(){
    
  }
  @logMethod
  getDate(...args:any[]){
    console.log(this.url)
  }
}
export class IceCreamComponent {

  toppings = [];

  @Confirmable('Are you sure?')
  @Confirmable('Are you super, super sure? There is no going back!')
  addTopping(topping) {
    this.toppings.push(topping);
  }

}


// Method Decorator
function Confirmable(message: string) {
  return function (target: Object, key: string | symbol, descriptor: PropertyDescriptor) {
    const original = descriptor.value;

      descriptor.value = function( ... args: any[]) {
          const allow = confirm(message);

          if (allow) {
            const result = original.apply(this, args);
            return result;
          } else {
            return null;
          }
    };

    return descriptor;
  };
}

方法參數(shù)裝飾器

可以使用參數(shù)裝飾器為類的原型增加一些元素?cái)?shù)據(jù),傳入下列3個(gè)參數(shù)

  1. 對(duì)于靜態(tài)成員來(lái)說(shuō)是類的構(gòu)造函數(shù),對(duì)于實(shí)例成員是類的原型對(duì)象
  2. 參數(shù)的名字
  3. 參數(shù)在函數(shù)參數(shù)列表中的索引
function logParams(parms:any){
  return function(target:any, methodName:any,paramsIndex:any){
    console.log(target)
    
    }
}
class HttpClient{
  public url:any|undefind;
  constructor(){
    
  }
  getData(@logParams('uuid') uuid:any){
    console.log(uuid)
  }
}

const http = new HttpClient()
http.getData(123456)

裝飾器的執(zhí)行順序

  • 如果同一個(gè)方法有多個(gè)裝飾器,會(huì)像剝洋蔥一樣,先從外到內(nèi)進(jìn)入,然后由內(nèi)向外執(zhí)行。復(fù)合函數(shù)的形式。

理解為包裹從同一類型裝飾器,從后往前

屬性>>方法>>方法參數(shù)>>類裝飾器

  1. 屬性裝飾器
  2. 方法裝飾器
  3. 方法參數(shù)裝飾器
  4. 類裝飾器

普通函數(shù)-高階函數(shù)的形式實(shí)現(xiàn)

function doSomething(name) {
  console.log('Hello, ' + name);
}

function loggingDecorator(wrapped) {
  return function() {
    console.log('Starting');
    const result = wrapped.call(this, ...arguments);
    console.log('Finished');
    return result;
  }
}

const wrapped = loggingDecorator(doSomething);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容