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以及用法相关推荐

  1. Typescript中的extends关键字

    前言 extends关键字在TS编程中出现的频率挺高的,而且不同场景下代表的含义不一样,特此总结一下: 表示继承/拓展的含义 表示约束的含义 表示分配的含义 基本使用 extends是 ts 里一个很 ...

  2. [ Typescript 手册] JavaScript `Array` 在 Typescript 中的接口

    [ Typescript 手册] JavaScript `Array` 在 Typescript 中的接口 本文地址:https://blog.csdn.net/qq_28550263/article ...

  3. typescript中的类型type与接口interface

    typescript中的type相当于是给类型起一个新的名字 基本用法: 比如我想声明一个类型为number的年龄age,刚开始学typescript,我们可能会这样写 let age:number ...

  4. 重载和重写的区别及在typescript中的使用

    在TypeScript中 重写(Override) 从字面上看,重写就是 重新写一遍的意思.其实就是在子类中把父类本身有的方法重新写一遍.子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中 ...

  5. 【进阶】TypeScript 中的 Type

    一 .什么是 TypeScript TypeScript 是静态编程语言 , 是 JavaScript 的超集 简而言之:JavaScript 有的 TypeScript 都有.JavaScript ...

  6. TypeScript中type和interface区别

    typescript中interface介绍:TypeScript 中的接口 interface_疆~的博客-CSDN博客通常使用接口(Interface)来定义对象的类型.https://blog. ...

  7. TypeScript 中的类型兼容性

    Typescript 乃 JavaScript 子集.只要设置一下编译器为非严格模式,那么所有 JavaScript 代码皆是合法的 TypeScript 代码.为了可以适应不同的场景 TypeScr ...

  8. TypeScript中的interface、type、class——泰联病从口入

    先看效果 type 和 interface 有什么异同? 1.interface侧重于描述数据结构,type侧重于描述类型 interface A{name:string; } type B = 'b ...

  9. 小记 TypeScript 中的循环引用问题

    随着项目规模的不断增长,循环引用问题似乎总是不可避免,本文就 TypeScript 中可能出现的循环引用问题做了一些简单记录~ 平时编写 TypeScript 代码时,一般都倾向于使用模块(Modul ...

  10. 1.1 typescript中的interface

    一.java中的interface java 1.interface中的除非静态.非default方法都是抽象方法,只有定义,没有实现 2.interface中的变量都是常量,被final stati ...

最新文章

  1. linux内存布局及页面映射
  2. 转:ESRI矢量数据格式简介
  3. 用神经网络分类远和近
  4. WindowsPhone 7.8 Tiles 3 : 7.8的Tiles利器mangopollo
  5. 关于if嵌套性能的问题
  6. 2009年上半年软考所有试题和答案公布 专家解析中
  7. 小程序定制开发和模板软件的区别和优势
  8. cad字体安装_一键自动替换CAD图纸缺失的字体
  9. WPS思维导图去除背景的网格
  10. 北京人口密度分布、人口趋势分析
  11. microsoft excel使用技巧和问题解决
  12. pytorch快速上手-使用自动标注软件Openlabeling和yolov5快速完成目标检测
  13. Geohash第三方库示例
  14. 网络打印机怎么和计算机连接不上,网络打印机无法连接怎么办?网络打印机设置步骤...
  15. 失眠怎么办?不妨试试这五款好物
  16. Matlab超声影像智能硬件
  17. Python 十进制到六进制
  18. 融资融券是对A股明显利好
  19. 【Esp32】Esp32+sx1268 Spi接口驱动SX1268模块
  20. eclipse中测试java_在Eclipse中使用JUnit进行单元测试

热门文章

  1. android 亮屏 激活自动亮度调节,Android 屏幕亮度调节(2.0以后出现亮度自动调节)如何开启、关闭亮度自动调节...
  2. 文本自动生成研究进展与趋势
  3. 解决win10桌面管理器内存泄漏问题
  4. Windows server2016 计算机管理中找不到用户和组
  5. 数据库学习(四)—SQL数据查询01(简单方法条件查询)
  6. Excel VBA为表格设置“打开文件密码”
  7. HDU1922 POJ3004 Subway planning “神题”留名
  8. winedit注册码
  9. Retrofit源码分析
  10. 【JAVA】Retrofit详解和使用