关于typescript中的extends和infer以及用法
创始人
2024-02-04 18:54:17
0

extends

extend的意思如果不是用在类的扩展中那么就表示约束在

type Pick = {[P in K]: T[P];
};

比如下面这个例子:
在这里插入图片描述

在Picks中K应该约束在keyof T这个类型中。

infer

infer表示占位符

逆变和协变

协变:子类型赋给父类型
逆变:父类型赋给子类型(设置strictFunctionTypes:true)
双向协变:父类型可以赋给子类型,子类型也可以赋给父类型

{}、Object和object

{} 是个空对象,没有索引,如果将某些内容注释为{},则可以是任何一种类型。
object 不能接收原始类型,而 {} 和 Object 都可以,这是它们的区别。
object 一般会用 Record 代替,约束索引类型更加语义化

&交叉类型

合并两个类型

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)

如果是非对象:

type res = 1 & string

在这里插入图片描述
此时合并的是never,所以非对象类型合并的必须是同类型

??和?可选链

??表示不为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才会获取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关键字为true的一侧
infer x可以理解成一个未知数x,表示待推断的函数参数

type Test = T extends (infer X)[] ? X : never;
// a类型为number | string
let a: Test = '10'

接下来带大家分析一个比较好的例子:

type ParseQueryString= Str extends `${infer Param}&${infer Rest}`// Param--a=1  Rest--b=2&c=3 // { a:1 }? MergeParams, ParseQueryString>: ParseParam;// 将a=1这种格式解析为对象{a:1}
type ParseParam =// a=1  Key--a  Value--1 // { a:1 }Param extends `${infer Key}=${infer Value}`? {[K in Key]: Value} : Record;// {a:1} {b:2,c:3} 用所有的key做对象,如果只是在其中一个对象那么就直接返回,否则合并两个对象的值
type MergeParams,OtherParam extends Record
> = {// ['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'同时约束在{a:1}和{b:2,c:3}那么就合并值返回一个列表? MergeValues// 否则返回{a:1}中的1: OneParam[Key]):// 'a'是否约束在{b:2,c:3}中,在就取出值否则不返回(Key extends keyof OtherParam? OtherParam[Key]: never)}type MergeValues =// 两个一样One extends Other? One// other是个列表: Other extends unknown[]// 合并列表? [One, ...Other]// 直接返回一个列表: [One, Other];function parseQueryString(queryStr: Str): ParseQueryString {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实现递归:

type ReverseStr = Str extends `${infer First}${infer Rest}`? ReverseStrFirst}${Result}`>: Result;const a = 'hello'
type b = ReverseStr

在这里插入图片描述

/*
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 = Arr['length'] extends Length? Arr: BuildArray;type Add =[...BuildArray, ...BuildArray]['length'];type addResult = BuildArray<10>

减法:

type Subtract = 
// 模式匹配占取部分值BuildArray extends [...arr1: BuildArray, ...arr2: infer Rest]? Rest['length']: never;
type dResult = Subtract<10,9>

乘法

type Mutiply = Num2 extends 0 ? ResultArr['length']: Mutiply, [...BuildArray, ...ResultArr]>;type mResult = Mutiply<11,10>

除法

type Divide = Num1 extends 0 ? CountArr['length']: Divide, Num2, [unknown, ...CountArr]>;

数组长度

type StrLen = Str extends `${string}${infer Rest}` ? StrLen : CountArr['length']

大于

type GreaterThan = Num1 extends Num2 ? false// CountArr长度是否等于Num2: CountArr['length'] extends Num2? true// CountArr长度是否等于Num1: CountArr['length'] extends Num1? false// 不断的加1去判断是否和Num1或者Num2相等,如果先和Num2相等,那就说明Num1是大于Num2的: GreaterThan;

过滤

type FilterString = {[Key in keyof T as T[Key] extends string ? Key: never]: T[Key];
}

as表示重命名,返回 never 代表过滤掉,否则保留。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...