typescript中的extends和infer使用及詳解
extends
extend的意思如果不是用在類的擴(kuò)展中那么就表示約束在。
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
比如下面這個(gè)例子:

在Picks中K應(yīng)該約束在keyof T這個(gè)類型中。
infer
infer表示占位符
逆變和協(xié)變
- 協(xié)變:子類型賦給父類型
- 逆變:父類型賦給子類型(設(shè)置strictFunctionTypes:true)
- 雙向協(xié)變:父類型可以賦給子類型,子類型也可以賦給父類型
{}、Object和object
- {} 是個(gè)空對(duì)象,沒有索引,如果將某些內(nèi)容注釋為{},則可以是任何一種類型。
- object 不能接收原始類型,而 {} 和 Object 都可以,這是它們的區(qū)別。
- object 一般會(huì)用 Record<string, any> 代替,約束索引類型更加語義化
&交叉類型
合并兩個(gè)類型
interface IPerson {
id: string;
age: number;
}
interface IWorker {
companyId: string;
}
type IStaff = IPerson & IWorker;
const staff: IStaff = {
id: 'E1006',
age: 33,
companyId: 'EXE'
};
console.dir(staff)
如果是非對(duì)象:
type res = 1 & string

此時(shí)合并的是never,所以非對(duì)象類型合并的必須是同類型
??和?可選鏈
??表示不為null并且不為undefined
const data = {
name:1
}
const dong = data.name ?? 'dog';
// 編譯后
"use strict";
var _a;
const data = {
name: 1
};
const dog = (_a = data.name) !== null && _a !== void 0 ? _a : 'dog';
可以看到是表示不為null和undefined才會(huì)獲取data.name否則是’dog’。
?表示為null或者是undefined和??剛好相反
const data = {
name:1
}
const dong = data?.name;
// 編譯后
"use strict";
const data = {
name: 1
};
const dong = data === null || data === void 0 ? void 0 : data.name;
可以看到?首先判斷是不是null或者undefined,如果是則返回undefined,否則返回data.name。
keyof any

infer和extends
- infer只能在extends關(guān)鍵字為true的一側(cè)
- infer x可以理解成一個(gè)未知數(shù)x,表示待推斷的函數(shù)參數(shù)
type Test<T> = T extends (infer X)[] ? X : never; // a類型為number | string let a: Test<number[] | string[]> = '10'
接下來帶大家分析一個(gè)比較好的例子:
type ParseQueryString<Str extends string>
= Str extends `${infer Param}&${infer Rest}`
// Param--a=1 Rest--b=2&c=3 // { a:1 }
? MergeParams<ParseParam<Param>, ParseQueryString<Rest>>
: ParseParam<Str>;
// 將a=1這種格式解析為對(duì)象{a:1}
type ParseParam<Param extends string> =
// a=1 Key--a Value--1 // { a:1 }
Param extends `${infer Key}=${infer Value}`
? {
[K in Key]: Value
} : Record<string, any>;
// {a:1} {b:2,c:3} 用所有的key做對(duì)象,如果只是在其中一個(gè)對(duì)象那么就直接返回,否則合并兩個(gè)對(duì)象的值
type MergeParams<
OneParam extends Record<string, any>,
OtherParam extends Record<string, any>
> = {
// ['a','b','c']
readonly [Key in keyof OneParam | keyof OtherParam]:
// 'a' 約束在{a:1}
Key extends keyof OneParam
// 'a'是否約束在{b:2,c:3}
?
(Key extends keyof OtherParam
// 如果'a'同時(shí)約束在{a:1}和{b:2,c:3}那么就合并值返回一個(gè)列表
? MergeValues<OneParam[Key], OtherParam[Key]>
// 否則返回{a:1}中的1
: OneParam[Key])
:
// 'a'是否約束在{b:2,c:3}中,在就取出值否則不返回
(Key extends keyof OtherParam
? OtherParam[Key]
: never)
}
type MergeValues<One, Other> =
// 兩個(gè)一樣
One extends Other
? One
// other是個(gè)列表
: Other extends unknown[]
// 合并列表
? [One, ...Other]
// 直接返回一個(gè)列表
: [One, Other];
function parseQueryString<Str extends string>(queryStr: Str): ParseQueryString<Str> {
if (!queryStr || !queryStr.length) {
return {} as any;
}
const items = queryStr.split('&');
const queryObj: any = {};
items.forEach(item => {
const [key, value] = item.split('=');
if (queryObj[key]) {
if (Array.isArray(queryObj[key])) {
queryObj[key].push(value);
} else {
queryObj[key] = [queryObj[key], value]
}
} else {
queryObj[key] = value;
}
});
return queryObj
}
const res = parseQueryString('a=1&b=2&c=3')
console.log(res);

使用infer實(shí)現(xiàn)遞歸:
type ReverseStr<
Str extends string,
Result extends string = ''
> = Str extends `${infer First}${infer Rest}`
? ReverseStr<Rest, `${First}${Result}`>
: Result;
const a = 'hello'
type b = ReverseStr<typeof a>

/* Str = hello Result = '' First = h Rest = ello Str = ello Result = 'h' First = e Rest = llo Str = llo Result = 'eh' First = l Rest = lo Str = lo Result = 'leh' First = l Rest = o Str = o Result = 'lleh' First = o Rest = '' Str = '' Result = 'olleh' First = '' Rest = '' */
下面我們來看看綜合案例:
加法
type BuildArray< Length extends number, Ele = unknown, Arr extends unknown[] = [] > = Arr['length'] extends Length ? Arr : BuildArray<Length, Ele, [...Arr, Ele]>; type Add<Num1 extends number, Num2 extends number> = [...BuildArray<Num1>, ...BuildArray<Num2>]['length']; type addResult = BuildArray<10>
減法
type Subtract<Num1 extends number, Num2 extends number> =
// 模式匹配占取部分值
BuildArray<Num1> extends [...arr1: BuildArray<Num2>, ...arr2: infer Rest]
? Rest['length']
: never;
type dResult = Subtract<10,9>
乘法
type Mutiply<
Num1 extends number,
Num2 extends number,
ResultArr extends unknown[] = []
> = Num2 extends 0 ? ResultArr['length']
: Mutiply<Num1, Subtract<Num2, 1>, [...BuildArray<Num1>, ...ResultArr]>;
type mResult = Mutiply<11,10>
除法
type Divide<
Num1 extends number,
Num2 extends number,
CountArr extends unknown[] = []
> = Num1 extends 0 ? CountArr['length']
: Divide<Subtract<Num1, Num2>, Num2, [unknown, ...CountArr]>;
數(shù)組長(zhǎng)度
type StrLen<
Str extends string,
CountArr extends unknown[] = []
> = Str extends `${string}${infer Rest}`
? StrLen<Rest, [...CountArr, unknown]>
: CountArr['length']
大于
type GreaterThan<
Num1 extends number,
Num2 extends number,
CountArr extends unknown[] = []
// 是否相等
> = Num1 extends Num2
? false
// CountArr長(zhǎng)度是否等于Num2
: CountArr['length'] extends Num2
? true
// CountArr長(zhǎng)度是否等于Num1
: CountArr['length'] extends Num1
? false
// 不斷的加1去判斷是否和Num1或者Num2相等,如果先和Num2相等,那就說明Num1是大于Num2的
: GreaterThan<Num1, Num2, [...CountArr, unknown]>;
過濾
type FilterString<T> = {
[Key in keyof T as T[Key] extends string ? Key: never]: T[Key];
}
as表示重命名,返回 never 代表過濾掉,否則保留。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
JS實(shí)現(xiàn)的貪吃蛇游戲完整實(shí)例
這篇文章主要介紹了JS實(shí)現(xiàn)的貪吃蛇游戲,結(jié)合完整實(shí)例形式分析了javascript實(shí)現(xiàn)貪吃蛇游戲的具體步驟、原理與相關(guān)操作技巧,需要的朋友可以參考下2019-01-01
javascript實(shí)現(xiàn)點(diǎn)擊圖片切換
這篇文章主要介紹了javascript實(shí)現(xiàn)點(diǎn)擊圖片切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04
typescript返回值類型和參數(shù)類型的具體使用
本文主要介紹了typescript返回值類型和參數(shù)類型的具體使用文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
微信小程序動(dòng)態(tài)顯示項(xiàng)目倒計(jì)時(shí)
這篇文章主要為大家詳細(xì)介紹了微信小程序動(dòng)態(tài)顯示項(xiàng)目倒計(jì)時(shí),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06
uniapp小程序?qū)崙?zhàn)之利用騰訊地圖獲取定位
使用uniapp是因?yàn)樗且粋€(gè)使用vue.js開發(fā)所有前端應(yīng)用的框架,開發(fā)者編寫一套代碼,可以發(fā)布到ios,android,web以及各種小程序,快應(yīng)用等多個(gè)平臺(tái),下面這篇文章主要給大家介紹了關(guān)于uniapp小程序?qū)崙?zhàn)之利用騰訊地圖獲取定位的相關(guān)資料,需要的朋友可以參考下2023-02-02
javascript encodeURI和encodeURIComponent的比較
在進(jìn)行SaaS前端開發(fā)的時(shí)候,大家經(jīng)常會(huì)用到兩個(gè)JavaScriptNative函數(shù):encodeURI 和 encodeURIComponent。這篇文章詳細(xì)解釋這兩個(gè)函數(shù)的用途并比較它們的不同之處2010-04-04
js中string轉(zhuǎn)int把String類型轉(zhuǎn)化成int類型
今天碰到一個(gè)問題,需要把String類型的變量轉(zhuǎn)化成int類型的,js中String轉(zhuǎn)int和Java中不一樣,不能直接把Java中的用到j(luò)s中2014-08-08

