关于typescript中的extends和infer以及用法

news2024/11/17 16:04:35

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 代表过滤掉,否则保留。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/22566.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云原生安全系列2:关于镜像安全必须知道的事儿

1.避免特权容器 Docker 提供了一种特权模式&#xff0c;它允许容器在本地计算机上以 root 身份运行。在特权模式下运行容器提供了该主机的功能&#xff0c;包括&#xff1a; 对所有设备的根访问权限能够篡改 AppArmor 和 SELinux 等 Linux 安全模块能够使用主机的内核功能安装…

pytorch神经网络基本骨架nn.module的使用

1.Containers 首先查看官方文档中nn.module骨架&#xff0c;其中有六个模块。 1.1Module import torch.nn as nn import torch.nn.functional as F class Module(nn.Module):def __init__(self):super(Module, self).__init__()self.conv1nn.Conv2d(1, 20, 5)self.conv2nn.C…

ESP32学习笔记 - 基于 ESP32 移植 LVGL8.3

以前写过一篇文章,讲述了如何基于ESP32 芯片移植LVGL这个GUI框架,当时是在LVGL移植好的工程lv_port_esp32上进行的,这个工程最新支持到LVGL7.9版本,关于之前的移植文章,可以参考以下链接: ESP32学习笔记 - 移植LVGL 随着LVGL不断在高频率地迭代大版本,LVGL8.x已经比以…

java基于springboot+vue的酒店预订网站——计算机毕业设计

运行环境&#xff1a; 开发工具:IDEA /Eclipse 数据库:MYSQL5.7 应用服务:Tomcat7/Tomcat8 使用框架springbootvue 项目介绍 民宿管理平台系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商家管理、民宿信息管理、房间类型管理、房间信息管理、…

基于Springboot+Mybatis+mysql+vue技术交流博客论坛系统

基于SpringbootMybatismysqlvue技术交流博客论坛系统一、系统介绍二、功能展示1.主页(普通用户)2.登陆、注册&#xff08;普通用户&#xff09;3.博客(普通用户)4.文章详情&#xff08;点赞、评论&#xff09;&#xff08;普通用户&#xff09;5.我的文章&#xff08;普通用户&…

模拟电子技术(六)信号的运算与处理

&#xff08;六&#xff09;信号的运算与处理基本运算电路概述比例运算电路反向比例运算电路同相比例运算电路电压跟随器加减运算电路求和运算电路加减运算电路积分运算电路微分运算电路基本微分运算电路逆函数型微分运算电路对数运算电路采用二极管的对数运算电路利用晶体管的…

配置中心微服务(Spring Cloud Config)

为什么需要配置服务中心&#xff1f; 1、统一维护2、配置内容安全与权限微服务之config server 注册到注册中心启动类加注解&#xff1a;EnableConfigServerSpringCloudApplicationEnableDiscoveryClient/{name}-{profiles}.yml <>name 微服务名称 profiles…

【electron】 打包应用修改图标和进程名字

文章目录导读开发环境打包流程制作一个大于等于256*256的icon修改package.json执行 *npm run build* 生成应用效果图踩坑icon必现大于等于 256*256图片有损icon图标要包含各种分辨率的resources\app.asar占用参考资料导读 以下内容在https://gitee.com/zkyt/electron-vue-eleme…

CobaltStrike木马免杀代码篇之python反序列化分离免杀(一)

前言 本篇文章主要用到python来对CobaltStrike生成的Shellcode进行分离免杀处理, 因此要求读者要有一定的python基础, 下面我会介绍pyhon反序列化免杀所需用到的相关函数和库 exec函数 exec函数是python的内置函数, 其功能与eval()函数相同, 但不同的是exec函数支持多行pyth…

Metabase学习教程:提问-3

时间序列比较 如何使用自定义表达式进行同比或逐月比较。 一个强大但也许不明显的东西自定义表达式让我们做的就是创造时间序列比较。例如&#xff0c;如果我们想比较2019年和2018年的每月收入或每天的用户数&#xff0c;我们可以使用Sumif和Countif 聚合功能。 第一步&…

(HAL库)实验1 点亮一个LED

1、实验准备 实验目标&#xff1a;点亮LED 器材&#xff1a;海创stm32开发板和数据线 2、CubeMX初始化 2.1 新建工程 打开STM32CubeMX软件&#xff08;V6.6.1&#xff09;&#xff0c;点击左上角"File"&#xff0c;再点击“New Project”。 在出现的左上角搜索框…

【C语言】初识指针(二)

你可以改变你的行为&#xff0c;但改变不了你想要什么——《浴血黑帮》 目录 1、指针类型 1.1指针加减(、-)整数 1.2指针的解引用 2、野指针 2.1什么叫野指针 2.1.1指针未初始化 2.1.2指针越界访问 2.1.3指针指向的空间被释放了 2.2如何避免野指针 前言&#xff1a; 大…

150. 以前编写好能够正常运行的 SAP UI5 代码,几个月后忽然不能运行了该怎么办?

以笔者本套教材为例,每一步骤的源代码都托管在本人 Github 仓库里,每次上传之前,都确保本地测试通过。 但笔者编写过程中发现,之前测试通过的代码,可能几个月之后再执行,就会遇到白屏现象,即应用无法正常加载,或者无法在调试模式下正常加载。 举个具体的例子。本文写…

渗透测试——找寻绝对路径的方法总结

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

Nignx部署前端页面

1.在Linux找到nginx的配置 2.使用vim命令打开nginx.conf vim nginx.conf 3.找到server块 将server_name改为服务器ip地址 4.按照原有的location块新建一个同样的location块 如果有多个就新建多个 5.将要部署的前端页面上传到自己知道的linux中的位置 我这里是存放在 data/w…

靶场-DC

文章目录主机发现端口扫描扫描目录登录网页查看users库查看staff库&#xff08;密码正确&#xff09;爆破ssh端口敲门服务利用提权主机发现 nmap -sP 192.168.111.1/24 arpscan -l netdiscover -p 发现除了本机ip&#xff0c;速度快发现目标机的ip&#xff1a;192.168.111.140…

Go 语言变量

变量来源于数学&#xff0c;是计算机语言中能储存计算结果或能表示值抽象概念。 变量可以通过变量名访问。 Go 语言变量名由字母、数字、下划线组成&#xff0c;其中首个字符不能为数字。 声明变量的一般形式是使用 var 关键字&#xff1a; var identifier type 可以一次声…

基于PHP+MySQL新生报到管理系统(含论文)

每年都有大量的新生需要报到,但是很多时候因为是第一次到本校进行报到,不知道具体的报到流程和学校的安排,如果挨个的去通知无形之间会给工作人员增加工作量,目前最好的办法就是开发一套新生报到系统,让新生可以自己去查看具体的工作流程和安排 本系统是基于PHP和mysql来进行开…

九、数据库的备份还原

九、数据库的备份还原 1、归档管理 使用DM Manager&#xff1a; 点击注册的实例连接->右键->管理服务器 点击系统管理->点击配置->点击转换 点击归档配置->归档 使用DISQL&#xff1a; #创建文件夹存放日志文件 mkdir /dm/dmarch#登录disql disql SYSDBA SY…

细胞衰老——酪氨酸激酶抑制剂

20 世纪 60 年代&#xff0c;Hayflick 和 Moorhea 首次引入细胞衰老的概念&#xff0c;以描述正常的人类二倍体细胞株在连续培养后出现的不可逆的生长停滞现象。后来的研究表明&#xff0c;细胞衰老可由端粒缩短或功能障碍、致癌基因激活、DNA 损伤和突变&#xff0c;以及许多不…