TypeScript學習筆記(三)泛型、模組化和名稱空間

CodeReaper發表於2021-08-10

一、泛型

1. 泛型函式

function getMin<T>(arr: T[]):T {
    if(arr.length === 0) {
        throw new Error("輸入的陣列沒有元素"); 
    }
    let res: T = arr[0];
    for (let i = 1; i < arr.length; i++) {
        if(arr[i] < res) {
            res = arr[i];
        }
    }
    return res;
}

C++ 的泛型函式非常類似

2. 泛型類

下面這個類可以求出當前列表中最小的元素

class MinClass<T> {
    private dataArr: T[] = [];
    public add(...val: T[]): void {
        this.dataArr.push(...val);
    }
    public getMin(): T {
        if(this.dataArr.length === 0) {
            throw new Error("當前陣列沒有元素"); 
        }
        let res: T = this.dataArr[0];
        for (let i = 1; i < this.dataArr.length; i++) {
            if(this.dataArr[i] < res) {
                res = this.dataArr[i];
            }
        }
        return res;
    }
}

3. 泛型介面

寫法一

interface ConfigFn {
    <T>(value:T):T;
}
let getData:ConfigFn = function<T>(value:T):T {
    return value;
}
getData<string>("張三");

寫法二

interface ConfigFn<T> {
    (value:T): T;
}
function getData<T>(value:T) {
    return value;
}
var myGetData:ConfigFn<string> = getData;
myGetData("20");

兩種寫法的區別

  • 寫法一:一般用於在使用時才規定泛型的型別,用法類似泛型函式
  • 寫法二:一般用於約束函式引數傳遞的型別,類似 Java 中的:
public void func(List<Integer> array){
  ...
}

這樣的引數約束。

二、模組化

TypeScript 中一個 ts 檔案中的函式和變數都是該檔案私有的,只有通過 export 輸出才能被外部呼叫。

1. export寫法一

例如以下情況,我們希望暴露兩個函式供外部呼叫,可以這樣寫:

// db.ts
export function getData():any[] {
    console.log("獲取資料庫的資料");
    return [
        { title:"121312" },
        { title:"123123" }
    ]
}

export function save() {
    console.log("儲存資料成功")
}

在需要使用的地方使用 import 關鍵字進行引入,語法如下:

import { aaa,bbb } from "模組的路徑";

注意,引入時不需要加最後的 .ts 字尾名,示例如下:

// index.ts
import { getData,save } from "./05module";
let data:any[] = getData();
console.log(data);
save();

因為模組的輸出預設是以物件形式進行的(即所有export的東西都被封裝到一個物件中),所以如果我們希望直接使用其他模組的方法或欄位,需要使用 {} 運算子取出來再使用。

2. export寫法二

我們也可以將所有的東西統一輸出,避免編寫多個 export

function getData():any[] {
    console.log("獲取資料庫的資料");
    return [
        { title:"121312" },
        { title:"123123" }
    ]
}

function save() {
    console.log("儲存資料成功")
}

// 將所有需要輸出的東西包裝成物件
export {
    getData,
    save
}

3. 為引入的方法或變數起別名

當我們覺得引入的方法或變數的名字使用起來不太方便等時可以為它們起別名,使用 as 關鍵字:

import { save as saveData } from "./05module";
saveData();

4. export default的使用

一個模組中 export default 只能使用一次,一般當只希望暴露一個方法時可以使用,例如:

// db.ts
function getData():any[] {
    console.log("獲取資料庫的資料");
    return [
        { title:"121312" },
        { title:"123123" }
    ]
}
export default getData;

而此時的引入也不相同:

import getData from "./05module";
let data:any[] = getData();
console.log(data);

在引入的時候我們不需要使用 {} 操作符進行獲取了,此外我們 import 後面的變數名也不需要和export的變數相同:

import hello from "./05module";
let data:any[] = hello();
console.log(data);

這樣也是可以得到正確結果的

tips:使用 export 來匯出一個類的操作和匯出變數和方法的操作都是相同的,因為編譯成 js 程式碼後,一個類本質上就是一個建構函式,在 js 中函式就是一種變數型別,因此操作都是一致的。

三、名稱空間

語法:

namespace 名稱空間名 {
  ...
}

作用:一個模組內可以有多個名稱空間,不同名稱空間中的相同識別符號的變數、函式和類等等可以重名不發生衝突

匯出名稱空間:

export namespace A {
  ...
}

引入名稱空間的方法和引入變數及函式的方式一致。

tips:名稱空間中的內容預設都是私有的,即使匯出了名稱空間,但預設還是無法直接使用到名稱空間內部的函式的,需要將它們也export出來。

示例:

export namespace A {
    interface Animal {
        name: string;
        eat():void;
    }
    export class Dog implements Animal {
        name: string;
        constructor(name:string) {
            this.name = name;
        }
        eat(): void {
            console.log(`小狗${this.name}在吃狗糧`);
        }
    }
    export class Cat implements Animal {
        name: string;
        constructor(name:string) {
            this.name = name;
        }
        eat(): void {
            console.log(`小貓${this.name}在吃魚`);
        }
    }
}
  
let dog = new A.Dog("小黑");
dog.eat();
image-20210810125654550

相關文章