关于typescript中的extends和infer以及用法
extends
extend的意思如果不是用在类的扩展中那么就表示约束在
。
type Pick<T, K extends keyof T> = {[P in K]: T[P];
};
比如下面这个例子:
在Picks中K应该约束在keyof T这个类型中。
infer
infer表示占位符
逆变和协变
协变:子类型赋给父类型
逆变:父类型赋给子类型(设置strictFunctionTypes:true)
双向协变:父类型可以赋给子类型,子类型也可以赋给父类型
{}、Object和object
{} 是个空对象,没有索引,如果将某些内容注释为{},则可以是任何一种类型。
object 不能接收原始类型,而 {} 和 Object 都可以,这是它们的区别。
object 一般会用 Record<string, any> 代替,约束索引类型更加语义化
&交叉类型
合并两个类型
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> = T extends (infer X)[] ? X : never;
// a类型为number | string
let a: Test<number[] | string[]> = '10'
接下来带大家分析一个比较好的例子:
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这种格式解析为对象{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做对象,如果只是在其中一个对象那么就直接返回,否则合并两个对象的值
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'同时约束在{a:1}和{b:2,c:3}那么就合并值返回一个列表? 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> =// 两个一样One extends Other? One// other是个列表: Other extends unknown[]// 合并列表? [One, ...Other]// 直接返回一个列表: [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实现递归:
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]>;
数组长度
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长度是否等于Num2: CountArr['length'] extends Num2? true// CountArr长度是否等于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 代表过滤掉,否则保留。
关于typescript中的extends和infer以及用法相关推荐
- Typescript中的extends关键字
前言 extends关键字在TS编程中出现的频率挺高的,而且不同场景下代表的含义不一样,特此总结一下: 表示继承/拓展的含义 表示约束的含义 表示分配的含义 基本使用 extends是 ts 里一个很 ...
- [ Typescript 手册] JavaScript `Array` 在 Typescript 中的接口
[ Typescript 手册] JavaScript `Array` 在 Typescript 中的接口 本文地址:https://blog.csdn.net/qq_28550263/article ...
- typescript中的类型type与接口interface
typescript中的type相当于是给类型起一个新的名字 基本用法: 比如我想声明一个类型为number的年龄age,刚开始学typescript,我们可能会这样写 let age:number ...
- 重载和重写的区别及在typescript中的使用
在TypeScript中 重写(Override) 从字面上看,重写就是 重新写一遍的意思.其实就是在子类中把父类本身有的方法重新写一遍.子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中 ...
- 【进阶】TypeScript 中的 Type
一 .什么是 TypeScript TypeScript 是静态编程语言 , 是 JavaScript 的超集 简而言之:JavaScript 有的 TypeScript 都有.JavaScript ...
- TypeScript中type和interface区别
typescript中interface介绍:TypeScript 中的接口 interface_疆~的博客-CSDN博客通常使用接口(Interface)来定义对象的类型.https://blog. ...
- TypeScript 中的类型兼容性
Typescript 乃 JavaScript 子集.只要设置一下编译器为非严格模式,那么所有 JavaScript 代码皆是合法的 TypeScript 代码.为了可以适应不同的场景 TypeScr ...
- TypeScript中的interface、type、class——泰联病从口入
先看效果 type 和 interface 有什么异同? 1.interface侧重于描述数据结构,type侧重于描述类型 interface A{name:string; } type B = 'b ...
- 小记 TypeScript 中的循环引用问题
随着项目规模的不断增长,循环引用问题似乎总是不可避免,本文就 TypeScript 中可能出现的循环引用问题做了一些简单记录~ 平时编写 TypeScript 代码时,一般都倾向于使用模块(Modul ...
- 1.1 typescript中的interface
一.java中的interface java 1.interface中的除非静态.非default方法都是抽象方法,只有定义,没有实现 2.interface中的变量都是常量,被final stati ...
最新文章
- linux内存布局及页面映射
- 转:ESRI矢量数据格式简介
- 用神经网络分类远和近
- WindowsPhone 7.8 Tiles 3 : 7.8的Tiles利器mangopollo
- 关于if嵌套性能的问题
- 2009年上半年软考所有试题和答案公布 专家解析中
- 小程序定制开发和模板软件的区别和优势
- cad字体安装_一键自动替换CAD图纸缺失的字体
- WPS思维导图去除背景的网格
- 北京人口密度分布、人口趋势分析
- microsoft excel使用技巧和问题解决
- pytorch快速上手-使用自动标注软件Openlabeling和yolov5快速完成目标检测
- Geohash第三方库示例
- 网络打印机怎么和计算机连接不上,网络打印机无法连接怎么办?网络打印机设置步骤...
- 失眠怎么办?不妨试试这五款好物
- Matlab超声影像智能硬件
- Python 十进制到六进制
- 融资融券是对A股明显利好
- 【Esp32】Esp32+sx1268 Spi接口驱动SX1268模块
- eclipse中测试java_在Eclipse中使用JUnit进行单元测试
热门文章
- android 亮屏 激活自动亮度调节,Android 屏幕亮度调节(2.0以后出现亮度自动调节)如何开启、关闭亮度自动调节...
- 文本自动生成研究进展与趋势
- 解决win10桌面管理器内存泄漏问题
- Windows server2016 计算机管理中找不到用户和组
- 数据库学习(四)—SQL数据查询01(简单方法条件查询)
- Excel VBA为表格设置“打开文件密码”
- HDU1922 POJ3004 Subway planning “神题”留名
- winedit注册码
- Retrofit源码分析
- 【JAVA】Retrofit详解和使用