typescript類(lèi)型體操及關(guān)鍵字使用示例詳解
前言
事情是這樣的,有這樣一道 ts 類(lèi)型題,代碼如下所示:
type Union = "Mon" | "Tue" | "Wed";
// 補(bǔ)充這里的類(lèi)型代碼
type Mapping<T extends Union, Value extends string> = any;
type Res = Mapping<Union, "周一" | "周二" | "周三">;
// 以下是輸出結(jié)果
// {
// mon: "周一";
// Tue: "周二";
// Wed: "周三";
// }觀察題目,其實(shí)就是將兩個(gè)聯(lián)合類(lèi)型的值組合成接口,其中第一個(gè)聯(lián)合類(lèi)型的值作為屬性,第二個(gè)聯(lián)合類(lèi)型的值則作為屬性值,并且兩者的屬性順序是一一對(duì)應(yīng)的。下面跟著我一起來(lái)分析,通過(guò)這道題,我們能理解到 ts 的不少知識(shí)點(diǎn),不信繼續(xù)往下看。
分析
實(shí)際上,在 ts 當(dāng)中,想要保證 ts 的順序是很困難的,這與 ts 編譯器有關(guān),不過(guò)這不影響我們對(duì)這道題的分析,那么這道題如何解決呢?思路就是想辦法將 2 個(gè)聯(lián)合類(lèi)型構(gòu)造成數(shù)組,然后就可以根據(jù)數(shù)組項(xiàng)一一對(duì)應(yīng)來(lái)轉(zhuǎn)成對(duì)象了,那么這道題的難點(diǎn)在于如何轉(zhuǎn)成數(shù)組。
轉(zhuǎn)成數(shù)組的前提就是我們將聯(lián)合類(lèi)型的每一項(xiàng)取出來(lái)然后添加到數(shù)組中,那么如何提取呢?下面讓我們一步一步來(lái)實(shí)現(xiàn)。
將并集轉(zhuǎn)成交集
聯(lián)合類(lèi)型我們也可以叫做并集,如: 1 | 2 | 3,而要實(shí)現(xiàn)添加的第一步,我們需要將并集轉(zhuǎn)成交集,那么如何進(jìn)行交集的轉(zhuǎn)換呢?
其實(shí)我們可以將并集的每一項(xiàng)使用函數(shù)來(lái)推斷,在這里我們需要理解 ts 中的 2 個(gè)關(guān)鍵字用法,如下:
- extends: 既可以表示類(lèi)的繼承,也可以表示條件判斷(相當(dāng)于 js 的全等)。
- infer: 該關(guān)鍵字用于推導(dǎo)某個(gè)類(lèi)型。
根據(jù)以上分析,我們就可以實(shí)現(xiàn)并集轉(zhuǎn)成交集,代碼如下:
// X | Y | Z ==> X & Y & Z type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ( k: infer I ) => void ? I : never;
以上類(lèi)型就實(shí)現(xiàn)了并集對(duì)交集的轉(zhuǎn)換,理解起來(lái)也很容易,就是判斷給定的泛型參數(shù)是否是任意類(lèi)型 any,如果是則構(gòu)造成函數(shù)參數(shù)為該類(lèi)型,然后使用 infer 關(guān)鍵字去推導(dǎo)參數(shù)類(lèi)型,如果能推導(dǎo)出來(lái),則返回推導(dǎo)出來(lái)的結(jié)果,否則返回 never。
any 與 never 與 void 類(lèi)型
這個(gè) ts 類(lèi)型也涉及到了 3 個(gè)類(lèi)型,即任意類(lèi)型 any,從不類(lèi)型 never,和 void 類(lèi)型。
any 類(lèi)型
其中 any 用來(lái)表示允許賦值為任意類(lèi)型。在 ts 中,如果是一個(gè)普通類(lèi)型,在賦值過(guò)程中改變類(lèi)型是不被允許的。例如:
let a: string = "123"; a = 2; // error TS2322: Type 'number' is not assignable to type 'string'
以上定義 a 變量的類(lèi)型是 string,因此修改變量值為數(shù)值,則 ts 編譯會(huì)出錯(cuò),但如果是賦值為任意值類(lèi)型,則以上操作不會(huì)報(bào)錯(cuò),如下所示:
let a: any = "123"; a = 2; // 允許修改,因?yàn)槭侨我庵殿?lèi)型
我們也可以訪問(wèn)任意類(lèi)型的屬性和方法,如下所示:
let b: any = "b";
console.log(b.name); // ts編譯不會(huì)報(bào)錯(cuò)
console.log(b.setName("a")); // ts編譯不會(huì)出錯(cuò)也就是說(shuō),聲明一個(gè)變量為任意值之后,對(duì)它的任何操作,返回的內(nèi)容的類(lèi)型都是任意值。
在 ts 中,一個(gè)未聲明類(lèi)型的變量,也會(huì)被推導(dǎo)成任意類(lèi)型,如:
let a;
a = "a";
a = 2;
a.setName("b");
// 以上操作在ts中都不會(huì)報(bào)錯(cuò)never 類(lèi)型
never 類(lèi)型表示從不存在的類(lèi)型,比如一個(gè)函數(shù)拋出異常,它的返回類(lèi)型就是 never,如:
const fn = (msg: string) => throw new Error(msg); // never
void 類(lèi)型
void 類(lèi)型表示沒(méi)有返回值,通常用在沒(méi)有任何返回值的函數(shù)中。如:
const fn = (): void => {
alert(123);
};以上類(lèi)型是包裝成函數(shù)類(lèi)型推導(dǎo),對(duì)于函數(shù)有沒(méi)有返回值沒(méi)有任何意義,因此這里只需要使用 void 來(lái)代表返回值即可。
將聯(lián)合類(lèi)型轉(zhuǎn)換成重載函數(shù)類(lèi)型
下一步,我們就需要將聯(lián)合類(lèi)型轉(zhuǎn)換成重載函數(shù)類(lèi)型,例如:
X | Y ==> ((x: X)=>void) & ((y:Y)=>void)
我們要如何實(shí)現(xiàn)呢?其實(shí)就是將泛型參數(shù)包裝成函數(shù)類(lèi)型,然后再調(diào)用用前面的并集轉(zhuǎn)交集類(lèi)型,如下:
type UnionToOvlds<U> = UnionToIntersection< U extends any ? (f: U) => void : never >;
做這一步的目的是方便將聯(lián)合類(lèi)型中的每一項(xiàng)提取出來(lái),因此需要這個(gè)類(lèi)型,接下來(lái)我們就需要將聯(lián)合類(lèi)型的每一項(xiàng)取出來(lái),我們叫做 PopUnion 類(lèi)型。
從聯(lián)合類(lèi)型中取出每一個(gè)類(lèi)型
有了前面 2 個(gè)類(lèi)型的鋪墊,取出聯(lián)合類(lèi)型中的每一個(gè)類(lèi)型就很容易,我們只需要包裝成重載函數(shù)類(lèi)型,然后使用 infer 推斷函數(shù)參數(shù)類(lèi)型,返回參數(shù)類(lèi)型即可。代碼如下:
type PopUnion<U> = UnionToOvlds<U> extends (f: infer A) => void ? A : never;
能夠取出聯(lián)合類(lèi)型的每一個(gè)類(lèi)型,那么構(gòu)造成數(shù)組就很容易了,不過(guò)接下來(lái)還需要一個(gè)類(lèi)型,那就是判斷是否是聯(lián)合類(lèi)型,為此我們需要先實(shí)現(xiàn)這個(gè)類(lèi)型,即 IsUnion 類(lèi)型。
判斷是否是聯(lián)合類(lèi)型
判斷是否是聯(lián)合類(lèi)型比較簡(jiǎn)單,就是將類(lèi)型構(gòu)造成一個(gè)數(shù)組,然后使用兩個(gè)數(shù)組比較,不過(guò)我們需要比較的是原始泛型參數(shù)構(gòu)造成數(shù)組和轉(zhuǎn)成交集構(gòu)造成數(shù)組是否相等,相等則返回 false,否則返回 true。代碼如下:
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
聯(lián)合類(lèi)型轉(zhuǎn)數(shù)組
接下來(lái)就是聯(lián)合類(lèi)型轉(zhuǎn)數(shù)組類(lèi)型的實(shí)現(xiàn),首先我們需要用到上一節(jié)提到的判斷是否是聯(lián)合類(lèi)型,如果是聯(lián)合類(lèi)型,則使用 PopUnion 類(lèi)型提取聯(lián)合類(lèi)型的每一項(xiàng),注意這里是需要遞歸的提取剩余項(xiàng)的,直到不是剩余項(xiàng)不是聯(lián)合類(lèi)型為止,因此這里我們沒(méi)提取一項(xiàng),都需要使用 Exclude 類(lèi)型將聯(lián)合類(lèi)型中提取的排除掉,這樣就得到了剩余的聯(lián)合類(lèi)型,然后我們使用第二個(gè)參數(shù)來(lái)存儲(chǔ)結(jié)果,如果不是聯(lián)合類(lèi)型就直接添加到數(shù)組中。代碼如下所示:
type UnionToArray<T, A extends unknown[] = []> = IsUnion<T> extends true ? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]> : [T, ...A];
以上代碼我們使用泛型 A 是一個(gè)未知類(lèi)型的數(shù)組,并默認(rèn)賦值為空數(shù)組來(lái)存儲(chǔ)結(jié)果,相當(dāng)于我們是從聯(lián)合類(lèi)型當(dāng)中一項(xiàng)一項(xiàng)的提取出來(lái)然后添加到 A 結(jié)果數(shù)組中,最終返回的結(jié)果就是一個(gè)由聯(lián)合類(lèi)型每一項(xiàng)組成的數(shù)組。
Exclude 類(lèi)型
其中 Exclude 類(lèi)型是 ts 內(nèi)置類(lèi)型,不過(guò)要實(shí)現(xiàn)還是比較簡(jiǎn)單的,簡(jiǎn)單來(lái)說(shuō)就是如果兩個(gè)參數(shù)相等,則不返回類(lèi)型,否則返回原類(lèi)型。代碼如下:
type Exclude<T, U> = T extends U ? never : T;
獲取數(shù)組的長(zhǎng)度
接下來(lái)我們還需要比較兩個(gè)聯(lián)合類(lèi)型提取出來(lái)的數(shù)組長(zhǎng)度是否相同,為此我們需要先實(shí)現(xiàn)如何獲取一個(gè)數(shù)組類(lèi)型的長(zhǎng)度,觀察發(fā)現(xiàn)數(shù)組是存在一個(gè) length 屬性的,因此我們可以判斷如果存在 length 屬性,并使用 infer 推斷具體值,能夠推斷出來(lái)就返回這個(gè)推斷的值,否則返回 never,代碼如下:
type Length<T extends ReadonlyArray<any>> = T extends { length: infer L }
? L
: never;這個(gè)代碼有一個(gè)類(lèi)型即 ReadonlyArray 類(lèi)型,它也是 ts 的一個(gè)內(nèi)置類(lèi)型,表示數(shù)組項(xiàng)只讀的數(shù)組,那么這個(gè)類(lèi)型是如何實(shí)現(xiàn)的呢?
ReadonlyArray 數(shù)組類(lèi)型
這個(gè)類(lèi)型的實(shí)現(xiàn)還是很簡(jiǎn)單的,就是只讀數(shù)組只有一個(gè) at 方法,數(shù)組 at 方法的作用就是獲取一個(gè)整數(shù)值并返回該索引處的項(xiàng)目,允許參數(shù)是正整數(shù)和負(fù)整數(shù),負(fù)整數(shù)從數(shù)組的最后一項(xiàng)開(kāi)始倒數(shù)。因此我們需要先實(shí)現(xiàn)這個(gè)只有 at 方法的接口,代碼如下:
interface RelativeIndexable<T> {
at(index: number): T | undefined;
}而只讀數(shù)組類(lèi)型 ReadonlyArray 只需要繼承這個(gè)接口就行了,代碼如下:
interface ReadonlyArray<T> extends RelativeIndexable<T> {}實(shí)現(xiàn)比較兩個(gè)數(shù)組長(zhǎng)度的類(lèi)型
有了能夠獲取數(shù)組長(zhǎng)度的類(lèi)型,接下來(lái)比較兩個(gè)數(shù)組長(zhǎng)度的類(lèi)型就很簡(jiǎn)單了,代碼如下:
type CompareLength< T extends ReadonlyArray<any>, U extends ReadonlyArray<any> > = Length<T> extends Length<U> ? true : false;
簡(jiǎn)單來(lái)說(shuō),就是兩個(gè)數(shù)組長(zhǎng)度一樣就返回 true,否則返回 false,這也限制了我們最終實(shí)現(xiàn)的類(lèi)型 2 個(gè)參數(shù)的聯(lián)合類(lèi)型最終提取出來(lái)的元素一定要一樣。
將屬性構(gòu)造成接口
接下來(lái)我們要實(shí)現(xiàn)將屬性構(gòu)造成接口,要想構(gòu)造成接口,那就需要屬性和屬性值,因此這個(gè)類(lèi)型的實(shí)現(xiàn)是有 2 個(gè)參數(shù)的,可以看到我們最終實(shí)現(xiàn)的 Mapping 就是有 2 個(gè)參數(shù),第一個(gè)參數(shù)作為屬性,第二個(gè)參數(shù)作為屬性值。而由于接口屬性類(lèi)型有限制,即只能是 PropertyKey 類(lèi)型,因此我們是需要判斷的,同理,為了實(shí)現(xiàn)屬性和屬性值一一對(duì)應(yīng)有值的情況下,我們也需要對(duì)第二個(gè)參數(shù)做判斷,只有滿足 2 個(gè)參數(shù)類(lèi)型都是 PropertyKey 類(lèi)型,才能構(gòu)造成接口,并且構(gòu)造成接口我們可以使用 Record 類(lèi)型。
根據(jù)以上分析,我們的最終代碼就實(shí)現(xiàn)如下:
// 不一定要叫Callback,也可以叫名字
type Callback<T, U> = T extends PropertyKey
? U extends PropertyKey
? Record<T, U>
: never
: never;以上還涉及到了 ts 的兩個(gè)內(nèi)置類(lèi)型,第一個(gè)是 PropertyKey 類(lèi)型,第二個(gè)則是Record<T,U>類(lèi)型,下面我們來(lái)一一看下這 2 個(gè)類(lèi)型的實(shí)現(xiàn)。
PropertyKey 類(lèi)型
第一個(gè) PropertyKey 類(lèi)型非常簡(jiǎn)單,它表示對(duì)象的屬性類(lèi)型,我們只需要知道 js 對(duì)象的屬性只能是字符串或者數(shù)字或者符號(hào)就可以知道這個(gè)類(lèi)型的實(shí)現(xiàn),代碼如下:
type PropertyKey = string | number | symbol;
可以看到這就是一個(gè)聯(lián)合類(lèi)型,屬性的類(lèi)型只能是字符串或者數(shù)值或者符號(hào)。
Record 類(lèi)型
Record 類(lèi)型表示構(gòu)造一個(gè)構(gòu)造一個(gè)具有類(lèi)型 T 的一組屬性 U 的類(lèi)型,我們只需要使用 in 操作符即可實(shí)現(xiàn),因?yàn)檫@個(gè)類(lèi)型的第一個(gè)參數(shù)是要作為接口屬性的,而第二個(gè)參數(shù)則是作為對(duì)應(yīng)的屬性值。代碼如下:
type Record<T extends keyof any, U> = {
[K in T]: U;
};這就是 Record 類(lèi)型的實(shí)現(xiàn),這其中還設(shè)計(jì)到了 ts 的一個(gè)關(guān)鍵字,即 keyof,它表示提取類(lèi)型的屬性,這個(gè)關(guān)鍵字通常用來(lái)提取接口的屬性,最后會(huì)返回組成屬性的聯(lián)合類(lèi)型。例如:
type Test = {
a: string;
1: number;
};
type TestKey = keyof Test; // 'a' | 1將兩個(gè)數(shù)組類(lèi)型構(gòu)造成接口
有了前面的幾個(gè)類(lèi)型的實(shí)現(xiàn),接下來(lái)我們需要實(shí)現(xiàn)一個(gè)根據(jù) 2 個(gè)參數(shù)數(shù)組構(gòu)造成接口的類(lèi)型,為此我們需要定義第三個(gè)參數(shù),第三個(gè)參數(shù)應(yīng)該是一個(gè)接口對(duì)象,用來(lái)當(dāng)作最終返回的結(jié)果,默認(rèn)是一個(gè)空對(duì)象,而前面 2 個(gè)參數(shù)就是我們的屬性組成的只讀數(shù)組。結(jié)構(gòu)如下所示:
type Zip<
T extends ReadonlyArray<any>,
U extends ReadonlyArray<any>,
R extends Record<string, any> = {}
> = any;接下來(lái)第一步,首先我們需要比較 2 個(gè)參數(shù)數(shù)組長(zhǎng)度應(yīng)該是一樣的,不一樣,我們就直接返回 never。如下所示:
type Zip<
T extends ReadonlyArray<any>,
U extends ReadonlyArray<any>,
R extends Record<string, any> = {}
> = CompareLength<T, U> extends true ? any : never;ps: 以上包括后面用 any 表示我們還沒(méi)有實(shí)現(xiàn),起一個(gè)占位符作用,方便我們理解實(shí)現(xiàn)思路。
緊接著第二步,我們需要判斷是否是空數(shù)組,只需要判斷其中一個(gè)即可,因?yàn)槲覀円呀?jīng)判斷了兩個(gè)數(shù)組長(zhǎng)度是否相等,如果其中一個(gè)是空數(shù)組,那么另一個(gè)必定也是空數(shù)組,如果是空數(shù)組,直接返回結(jié)果即可,此時(shí)默認(rèn)值就是空對(duì)象,直接返回結(jié)果也合理,代碼如下:
type Zip<
T extends ReadonlyArray<any>,
U extends ReadonlyArray<any>,
R extends Record<string, any> = {}
> = CompareLength<T, U> extends true ? (T extends [] ? R : any) : never;接下來(lái)第三步,我們還需要做判斷,那就是如果 2 個(gè)數(shù)組都只有一個(gè)數(shù)組項(xiàng),那么我們只需要將第一個(gè)數(shù)組項(xiàng)提取出來(lái),這里當(dāng)然是使用 infer 關(guān)鍵字來(lái)推導(dǎo)數(shù)組項(xiàng),然后使用 Callback 類(lèi)型構(gòu)造成接口并與 R 結(jié)果取并集即可。代碼如下所示:
type Zip<
T extends ReadonlyArray<any>,
U extends ReadonlyArray<any>,
R extends Record<string, any> = {}
> = CompareLength<T, U> extends true
? T extends []
? R
: T extends [infer F1]
? U extends [infer F2]
? R & Callback<F1, F2>
: never
: any
: never;第四步就是如果數(shù)組有多個(gè)數(shù)組項(xiàng),則我們需要遞歸的取并集。代碼如下所示:
type Zip<
T extends ReadonlyArray<any>,
U extends ReadonlyArray<any>,
R extends Record<string, any> = {}
> = CompareLength<T, U> extends true
? T extends []
? R
: T extends [infer F1]
? U extends [infer F2]
? R & Callback<F1, F2>
: never
: T extends [infer F1, ...infer T1]
? U extends [infer F2, ...infer T2]
? Zip<T1, T2, R & Callback<F1, F2>>
: never
: never
: never;雖然這個(gè)類(lèi)型的實(shí)現(xiàn)代碼比較長(zhǎng),但其實(shí)我們逐一拆分下來(lái)理解起來(lái)還是比較容易的。
實(shí)現(xiàn) Mapping 類(lèi)型
有了前面幾個(gè)類(lèi)型的實(shí)現(xiàn),最終我們就可以解答這道題了,我們只需要將 2 個(gè)聯(lián)合類(lèi)型構(gòu)造成 2 個(gè)數(shù)組,然后使用 Zip 類(lèi)型將 2 個(gè)類(lèi)型組成的數(shù)組轉(zhuǎn)成接口即可,代碼如下:
type Mapping<T extends Union, Value extends string> = Zip< UnionToArray<T>, UnionToArray<Value> >;
以上代碼很好理解,我們將 2 個(gè)聯(lián)合類(lèi)型使用 UnionToArray 構(gòu)造成 2 個(gè)類(lèi)型數(shù)組,然后使用 Zip 類(lèi)型構(gòu)造成接口。
優(yōu)化
不過(guò)以上代碼的實(shí)現(xiàn)還不算完美,因?yàn)槲覀冏罱K的結(jié)果是使用 Record 類(lèi)型展示的,并不直觀,因此最后一步,我們還需要將 Record 類(lèi)型轉(zhuǎn)成可以直觀看到的接口類(lèi)型,很簡(jiǎn)單,只需要讀取每一個(gè)接口屬性即可,和 Record 類(lèi)型實(shí)現(xiàn)原理很類(lèi)似。代碼如下:
type ToObj<T> = {
[K in keyof T]: T[K];
};最終實(shí)現(xiàn)版本
將優(yōu)化后的代碼與前面的實(shí)現(xiàn)合并,就得到了我們的最終實(shí)現(xiàn),代碼如下:
type Mapping<T extends Union, Value extends string> = ToObj< Zip<UnionToArray<T>, UnionToArray<Value>> >;
下面,我們將以上所有實(shí)現(xiàn)代碼整理到一起,代碼如下:
// 第一步
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
// 第二步
type UnionToOvlds<U> = UnionToIntersection<
U extends any ? (f: U) => void : never
>;
// 第三步
type PopUnion<U> = UnionToOvlds<U> extends (f: infer A) => void ? A : never;
// 第四步
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
// 第五步
type UnionToArray<T, A extends unknown[] = []> = IsUnion<T> extends true
? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
: [T, ...A];
// 第六步
type Length<T extends ReadonlyArray<any>> = T extends { length: infer L }
? L
: never;
// 第七步
type CompareLength<
T extends ReadonlyArray<any>,
U extends ReadonlyArray<any>
> = Length<T> extends Length<U> ? true : false;
// 第八步
type Callback<T, U> = T extends PropertyKey
? U extends PropertyKey
? Record<T, U>
: never
: never;
// 第九步
type Zip<
T extends ReadonlyArray<any>,
U extends ReadonlyArray<any>,
R extends Record<string, any> = {}
> = CompareLength<T, U> extends true
? T extends []
? R
: T extends [infer F1]
? U extends [infer F2]
? R & Callback<F1, F2>
: never
: T extends [infer F1, ...infer T1]
? U extends [infer F2, ...infer T2]
? Zip<T1, T2, R & Callback<F1, F2>>
: never
: never
: never;
// 第十步
type ToObj<T> = {
[K in keyof T]: T[K];
};
// 最終
type Mapping<T extends Union, Value extends string> = ToObj<
Zip<UnionToArray<T>, UnionToArray<Value>>
>;總結(jié)
下面我們來(lái)總結(jié)一下這道題中我們學(xué)到的知識(shí)點(diǎn):
- extends 關(guān)鍵字用于條件判斷。
- infer 關(guān)鍵字用于推導(dǎo)類(lèi)型。
- keyof 關(guān)鍵字用于獲取對(duì)象接口屬性。
- ts 類(lèi)型遞歸。
- ts 中的 3 個(gè)基本類(lèi)型的含義,即 any,never,void 的含義。
- ts 中內(nèi)置類(lèi)型的實(shí)現(xiàn),如: ReadonlyArray,Exclude,PropertyKey,Record。
以上的知識(shí)點(diǎn),在 ts 類(lèi)型體操當(dāng)中將會(huì)經(jīng)常用到,所以需要理解深刻。
只是一道題目,我們就學(xué)到了 ts 的很多類(lèi)型體操的知識(shí),ts 類(lèi)型這么有趣,難道不是嗎?
更多關(guān)于typescript類(lèi)型體操的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- typescript返回值類(lèi)型和參數(shù)類(lèi)型的具體使用
- Typescript中函數(shù)類(lèi)型及示例詳解
- TypeScript中類(lèi)型映射的使用
- TypeScript中d.ts類(lèi)型聲明文件的實(shí)現(xiàn)
- TypeScript中的類(lèi)型運(yùn)算符實(shí)現(xiàn)
- TypeScript基本類(lèi)型 typeof 和keyof案例詳解
- 淺聊一下TypeScript中的4種類(lèi)型守衛(wèi)
- typescript?type類(lèi)型使用梳理總結(jié)
- TypeScript 獲取函數(shù)的參數(shù)類(lèi)型、返回值類(lèi)型及定義返回函數(shù)類(lèi)型
相關(guān)文章
TypeScript 基本數(shù)據(jù)類(lèi)型實(shí)例詳解
這篇文章主要為大家介紹了TypeScript 基本數(shù)據(jù)類(lèi)型實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
數(shù)據(jù)結(jié)構(gòu)TypeScript之鏈表實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了數(shù)據(jù)結(jié)構(gòu)TypeScript之鏈表實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
數(shù)據(jù)結(jié)構(gòu)TypeScript之棧和隊(duì)列詳解
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)TypeScript之棧和隊(duì)列詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
TS中Array.reduce提示沒(méi)有與此調(diào)用匹配的重載解析
這篇文章主要為大家介紹了TS中Array.reduce提示沒(méi)有與此調(diào)用匹配的重載解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
TypeScript 高級(jí)數(shù)據(jù)類(lèi)型實(shí)例詳解
這篇文章主要為大家介紹了TypeScript 高級(jí)數(shù)據(jù)類(lèi)型實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
移動(dòng)設(shè)備web開(kāi)發(fā)首選框架:zeptojs介紹
這篇文章主要介紹了移動(dòng)設(shè)備web開(kāi)發(fā)首選框架:zeptojs介紹,他兼容jquery的API,所以學(xué)起來(lái)或用起來(lái)并不吃力,需要的朋友可以參考下2015-01-01

