typescript中高級類型Record

ts文檔上對Record的介紹不多,但卻經常用到,Record是一個很好用的工具類型。
他會將一個類型的所有屬性值都映射到另一個類型上並創造一個新的類型,先看下Record的源碼。

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

好像源碼也比較簡單,即將K中的每個屬性([P in K]),都轉爲T類型。常用的格式如下:

type proxyKType = Record<K,T>

會將K中的所有屬性值都轉換爲T類型,並將返回的新類型返回給proxyKType,K可以是聯合類型、對象、枚舉…
看幾個demo.
demo1:

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

type IPets = Record<petsGroup, IPetInfo>;

const animalsInfo:IPets = {
    dog:{
        name:'dogName',
        age:2
    },
    cat:{
        name:'catName',
        age:3
    },
    fish:{
        name:'fishName',
        age:5
    }
}

可以看到 IPets 類型是由 Record<petsGroup, IPetInfo>返回的。將petsGroup中的每個值(‘dog’ | ‘cat’ | ‘fish’)都轉爲 IPetInfo 類型。
當然也可以自己在第一個參數後追加額外的值,看下面demo2

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

type IPets = Record<petsGroup | 'otherAnamial', IPetInfo>;

const animalsInfo:IPets = {
    dog:{
        name:'dogName',
        age:2
    },
    cat:{
        name:'catName',
        age:3
    },
    fish:{
        name:'fishName',
        age:5
    },
    otherAnamial:{
        name:'otherAnamialName',
        age:10
    }
}

可以看到在demo1的基礎上,demo2在
type IPets = Record<petsGroup | ‘otherAnamial’, IPetInfo>; 中除了petsGroup的值之外,還追加了 'otherAnamial’這個值。
下面看一個略複雜的例子,用axios將http的幾個請求封裝一下,使用Record定義每個請求方法的形狀。

enum IHttpMethods {
    GET = 'get',
    POST = 'post',
    DELETE = 'delete',
    PUT = 'put',
}

const methods = ["get", "post", "delete", "put"];

interface IHttpFn {
    <T = any>(url: string, config?: AxiosRequestConfig): Promise<T>
}

type IHttp = Record<IHttpMethods, IHttpFn>;

const httpMethods: IHttp = methods.reduce((map: any, method: string) => {
    map[method] = (url: string, options: AxiosRequestConfig = {}) => {
        const { data, ...config } = options;
        return (axios as any)[method](url, data, config)
            .then((res: AxiosResponse) => {
                if (res.data.errCode) {
                    //todo somethins
                } else {
                    //todo somethins
                }
            });
    }
    return map
}, {})

export default httpMethods;

上面這個demo就先枚舉除了幾個常見的http請求的方法名,而每個方法都接受請求的url以及可選參數config,然後每個方法返回的都是一個Promise。這種業務常見使用Record再合適不過了。使用下面的方式定義了每個方法的形狀。

type IHttp = Record<IHttpMethods, IHttpFn>;

最後只需要遍歷一下幾個方法,對每個方法有各自的具體實現即可。這裏是用了reduce的特性,遍歷了一下數據,然後將所有的方法體放在一個對象中,最終結果用 httpMethods接受,再將httpMethods對外暴露出去,那麼外面就可直接調用了。這裏把一些業務的部分抽離出去了(比如設置請求頭、設置token之類的),只是爲了簡單說明一個比較合適使用Record的業務場景。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章