欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

typescript?type類型使用梳理總結(jié)

 更新時(shí)間:2023年08月18日 10:38:23   作者:goblin_pitcher  
這篇文章主要為大家介紹了typescript?type類型使用梳理總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

倉庫地址:https://github.com/goblin-pitcher/steel-wheel-run/blob/master/typescript/type-challenge-pre-content.md

最近準(zhǔn)備開始刷type-challenges,因此先梳理一下ts類型相關(guān)知識點(diǎn)。

遺漏知識點(diǎn)總結(jié)

ts的type符合圖靈完備。這意味著ts類型包含循環(huán)、判斷等一系列基本操作。

類型集合

類型應(yīng)當(dāng)作集合來看,其中:

unknown是全集,包含所有類型,是所有類型的父級

之前在泛型中會寫Comp<T extends unknown>看來是有些多此一舉了...

never是空集,是所有類型的子集

ts的設(shè)計(jì)符合里氏替換原則,即子集可以替換所有父級,這意味著:

interface Parent {
  id: string;
}
// 符合里氏替換原則,不會報(bào)錯(cuò)
interface Child extends Parent {
  id: "childIdA"|"childIdB"; // "childIdA"|"childIdB"是string的子集
  key: number; // Parent中沒有key,該屬性是Parent的拓展
}
// 不符合里氏替換原則,報(bào)錯(cuò)
interface ChildError extends Parent {
  id: number; // number不是string的子集
}
type A = {a: string};
type B = {a: "A"|"a", b: number};
let a: A = {a: "xxx"};
let b: B = {a: "a", b: 2};
// 符合B是A的子集,該賦值符合里氏替換原則, 反之 b=a 會報(bào)錯(cuò)
a = b;

將TS的type看作編程語言

既然ts的type是圖靈完備的,那么它自然可以完成一切計(jì)算,因此可以看作是一門語言

函數(shù)

在類型語境中,可將泛型看做是函數(shù)

type Fn<T> = T; // 看作 const Fn = val => val;

循環(huán)

經(jīng)常可以在代碼中看到如下寫法:

type R = "A" | "B"
type T = {
  [k in R]: k
}

這里[k in R]可看做循環(huán)for(const k in R){}

借助此特性,可以完成如下操作:

type MyPick<T, K extends keyof T> = {
  [k in K]: T[k]
}
type A = MyPick<{a: string, b: number, c: boolean}, "a"|"c">

當(dāng)然這種循環(huán)只針對特定類型("a"|"b"這種),稍微復(fù)雜點(diǎn)的循環(huán)還是得通過遞歸實(shí)現(xiàn),例子的話,后面用ts type實(shí)現(xiàn)四則運(yùn)算時(shí)會用到。

條件語句

type支持三元運(yùn)算符,這個(gè)沒什么好說的。。

需要注意的是,type里沒有等號,但可以用extends代替等號

type Equal5<T> = T extends 5 ? true : false;

來點(diǎn)練習(xí)

// eq1: 實(shí)現(xiàn)`GetProp<Obj, K>`(獲取Obj[K]類型)
type GetProp<Obj, K> = K extends keyof Obj ? Obj[K] : undefined;
// eq2: 實(shí)現(xiàn)getName<User>
type GetName<User> = GetProp<User, "name">

extends也常和infer一起用于類型推斷。

例如

// 實(shí)現(xiàn)KeyOf
type KeyOf<T> = T extends {[k in infer U]: unknown} ? U : never;
// 實(shí)現(xiàn)ValueOf
type ValueOf<T> = T extends { [k in keyof T]: infer U } ? U : never;
// 實(shí)現(xiàn)Parameters和ReturnType
type FuncBase<F, C extends "params"|"return"> = F extends (...params: infer P) => infer R ? (C extends "params" ? P : R) : never;
type Params<F> = FuncBase<F, "params">;
type Return<F> = FuncBase<F, "return">;

賦值

賦值部分參看前面類型集合章節(jié),賦值要遵循里氏替換原則。

條件語句章節(jié)提到了infer,或許可以用infer實(shí)現(xiàn)解構(gòu)賦值。

// 需要實(shí)現(xiàn)類似js的const {name, ...extra} = user,求extra。(其實(shí)就是Omit方法)
type MyPick<Obj, T extends keyof Obj> = {[k in T]: Obj[k]};
type MyExclude<Obj, T extends keyof Obj> = keyof Obj extends T|(infer U extends keyof Obj) ? U : never;
type MyOmit<Obj, T extends keyof Obj> =  MyPick<Obj, MyExclude<Obj, T>>;
// 實(shí)現(xiàn)數(shù)組的解構(gòu)賦值const [A, ...extra] = arr;
type GetArrBase<T extends unknown[], C extends "first"|"rest"> = T extends [infer First, ...infer Rest] ? (C extends "first"?First: Rest): never;
type GetFirst<T extends unknown[]> = GetArrBase<T, "first">;
type GetRest<T extends unknown[]> = GetArrBase<T, "rest">;

對象

type的對象可以類比js中的對象,使用方法如下,注意最后一個(gè)例子

type Obj = {
  name: string;
  age: 20;
}
Obj["name"] // string;
Obj.age // Error
Obj["age"] // 20
Obj['name'|'age'] // string | 20 , 這個(gè)特性很重要?。?!

利用這個(gè)特性,可以完成如下功能

interface Test {
  a: string;
  b: number;
  c: boolean;
}
// 之前不知道這個(gè)特性時(shí),用infer也能達(dá)到同樣的效果,但實(shí)現(xiàn)不如這個(gè)直觀
type ValueOf<T> = T[keyof T];
type R = ValueOf<Test>;

數(shù)組

ts中的數(shù)組分為Array數(shù)組和Tuple元組。

Array數(shù)組是諸如string[]的寫法,類似java或其他語言的數(shù)組。

Tuple元組更像是js中的數(shù)組,寫法是[string, number, boolean]這種。

(注:js中不存在真正意義上的數(shù)組,數(shù)組是在內(nèi)存上開辟連續(xù)空間,每個(gè)單元格所占內(nèi)存都一樣,在js中,數(shù)組寫成['a', 5555, {a: 1}]都沒問題,顯然在實(shí)現(xiàn)上不是真正的開辟了連續(xù)內(nèi)存空間,應(yīng)該是用鏈表模擬的,為了解決鏈表本身查詢慢的問題,應(yīng)該是采用了跳表或者紅黑樹的方式組織的?)

數(shù)組中需要注意的點(diǎn)如下:

type A = string[];
type B = [string, number, boolean];
// =========================分割線==========================
// 重點(diǎn)注意!?。?
A[0]; // string
A[1]; // string
B[0]; // string
B[1]; // number;
B[0|2]; // string|boolean
// 注意以下寫法,為什么可以這么寫,因?yàn)閚umber是所有數(shù)字的集合
A[number]; // string
B[number]; // string | number | boolean
A["length"]; // number
B["length"]; // 3
// ts數(shù)組同樣可以像js數(shù)組那樣展開
type Spread<T extends unknown[]> = [...T]
Spread<[1,2,3]> // [1,2,3]

根據(jù)以上特性,很容易實(shí)現(xiàn)以下練習(xí):

// eq1: 實(shí)現(xiàn) `ItemOf`方法(獲取數(shù)組中項(xiàng)的類型)
type ItemOf<T extends unknown[]> = T[number];
// 之前不知道這個(gè)特性時(shí),用infer實(shí)現(xiàn)的代碼如下
type ItemOfByinfer<T> = T extends (infer N)[] ? N : never;
// eq2:實(shí)現(xiàn)`Append`方法
type Append<T extends unknown[], Ele> = [...T, Ele];
// eq3: 實(shí)現(xiàn)返回?cái)?shù)組length+1
// ts雖然無法實(shí)現(xiàn)加減運(yùn)算,但可以通過模擬生成對應(yīng)新類型,返回其屬性,從而模擬加減運(yùn)算
type LengthAddOne<T extends unknown[]> = [unknown, ...T]["length"];

四則運(yùn)算

運(yùn)算加減依賴于元組長度,因此先定義一些基本方法,注意..由于是依賴元組長度,因此無法算負(fù)數(shù)和小數(shù),只能算正整數(shù)...

(注:雖然無法計(jì)算負(fù)數(shù)和小數(shù),但ts的type依舊是圖靈完備的,位運(yùn)算也只是01的運(yùn)算,負(fù)數(shù)和小數(shù)都是一堆01的定義,比如把10000看做0,且最后兩位是小數(shù),那么9999就是 -0.01)

// 返回Push后的數(shù)組
type Append<T extends unknown[], E = unknown> = [...T, U];
// 同理,返回Pop后的數(shù)組代碼如下,暫時(shí)用不到
// type RemoveTop<T extends unknown[]> = T extends [...(infer U), unknown] ? U : never;
type Tuple<N extends number, Arr extends unknown[] = []> = Arr["length"] extends N ? Arr : Tuple<N, Append<Arr>>

有了這些基本方法,先實(shí)現(xiàn)加法減法

type Add<A extends number, B extends number> = [...Tuple<A>, ...Tuple<B>]["length"];
type Subtract<A extends number, B extends number> = Tuple<A> extends [...Tuple<B>, ...(infer U)] ? U["length"] : never;

乘法的話,A*B就是A個(gè)B相加,簡易版乘法如下,思路不難,但直接用Add和Subtract封裝,很多寫法都提示嵌套太深。。

注意,這里用于統(tǒng)計(jì)和的參數(shù)S以元組表示,因?yàn)樗羞\(yùn)算都是以元組為基準(zhǔn),S用數(shù)字表示會先轉(zhuǎn)元組再轉(zhuǎn)數(shù)字,來來回回開銷比較大。

type MultipleBase<A extends number, B extends number, S extends unknown[] = []> = 
    B extends 0
    ? S["length"]
    : MultipleBase<A, Subtract<B, 1>, [...S, ...Tuple<A>]>;

乘法還有優(yōu)化的空間,例如2*100,直接用這個(gè)算的是100個(gè)2相加,時(shí)間復(fù)雜度不如100*2,而計(jì)算這么優(yōu)化的前提是,實(shí)現(xiàn)BiggerThan方法。

type BiggerThan<A extends number, B extends number> = Tuple<A> extends [...Tuple<B>, ...infer U] ? (U["length"] extends (never|0) ? false : true): false;
// 優(yōu)化后的乘法如下
type Mutiple<A extends number, B extends number> = BiggerThan<A, B> extends true ? MultipleBase<A, B> : MultipleBase<B, A>;

有了BiggerThan,除法也好說,例如a/b,判定b*2、b*3...b*n和A的大小就行。

同乘法的實(shí)現(xiàn),用于統(tǒng)計(jì)的參數(shù)R為元組。。

type Divide<A extends number, B extends number, R extends unknown[] = []> = BiggerThan<B, A> extends true ? R["length"] : Divide<Subtract<A,B>, B, Append<R>>;

至此,四則運(yùn)算實(shí)現(xiàn)完畢。

以上就是typescript type類型使用梳理總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于typescript type類型的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Typescript tsconfig.json的配置詳情

    Typescript tsconfig.json的配置詳情

    這篇文章主要為大家介紹了Typescript tsconfig.json的配置詳情示例 ,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Nest框架中集成使用Swagger示例說明

    Nest框架中集成使用Swagger示例說明

    這篇文章主要為大家介紹了Nest框架中集成使用Swagger的示例說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • typescript難學(xué)嗎?前端有必要學(xué)?該怎么學(xué)typescript

    typescript難學(xué)嗎?前端有必要學(xué)?該怎么學(xué)typescript

    TypeScript代碼與?JavaScript?代碼有非常高的兼容性,無門檻,你把?JS?代碼改為?TS?就可以運(yùn)行。TypeScript?應(yīng)該不會脫離?JavaScript?成為獨(dú)立的語言。學(xué)習(xí)?TypeScript?應(yīng)該主要指的是學(xué)習(xí)它的類型系統(tǒng)。
    2022-12-12
  • TypeScript交叉運(yùn)算的算法示例解析

    TypeScript交叉運(yùn)算的算法示例解析

    這篇文章主要為大家介紹了TypeScript交叉運(yùn)算的算法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • TypeScript十大排序算法插入排序?qū)崿F(xiàn)示例詳解

    TypeScript十大排序算法插入排序?qū)崿F(xiàn)示例詳解

    這篇文章主要為大家介紹了TypeScript十大排序算法插入排序?qū)崿F(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • d3-scale d3-scaleTime使用示例詳解

    d3-scale d3-scaleTime使用示例詳解

    這篇文章主要為大家介紹了d3-scale d3-scaleTime使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Typescript?extends?關(guān)鍵字繼承類型約束及條件類型判斷實(shí)現(xiàn)示例解析

    Typescript?extends?關(guān)鍵字繼承類型約束及條件類型判斷實(shí)現(xiàn)示例解析

    這篇文章主要介紹了Typescript?extends?關(guān)鍵字繼承類型約束及條件類型判斷實(shí)現(xiàn)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • TypeScript中的聯(lián)合類型使用示例詳解

    TypeScript中的聯(lián)合類型使用示例詳解

    這篇文章主要為大家介紹了TypeScript中的聯(lián)合類型使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • typescript快速上手的基礎(chǔ)知識篇

    typescript快速上手的基礎(chǔ)知識篇

    靜態(tài)類型的typescript與傳統(tǒng)動態(tài)弱類型語言javascript不同,在執(zhí)行前會先編譯成javascript,因?yàn)樗鼜?qiáng)大的type類型系統(tǒng)加持,能讓我們在編寫代碼時(shí)增加更多嚴(yán)謹(jǐn)?shù)南拗?。注意,它并不是一門全新的語言,所以并沒有增加額外的學(xué)習(xí)成本
    2022-12-12
  • TypeScript十大排序算法之選擇排序?qū)崿F(xiàn)示例詳解

    TypeScript十大排序算法之選擇排序?qū)崿F(xiàn)示例詳解

    這篇文章主要為大家介紹了TypeScript十大排序算法之選擇排序?qū)崿F(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02

最新評論