TypeScript体操(二):Utility Type手写实现

news2024/11/16 5:45:31

目录

    • 前言
    • 常用 Utility Types 及其实现
      • `Partial<T>`
      • `Required<T>`
      • `Readonly<T>`
      • `Pick<T, K>`
      • `Omit<T, K>`
      • `Record<K, T>`
      • `Exclude<T, U>`
      • `Extract<T, U>`
      • `NonNullable<T>`
      • `ReturnType<T>`
      • `InstanceType<T>`
      • `Parameters<T>`
      • `ConstructorParameters<T>`
      • `Awaited<T>`
    • 结语

前言

上一篇文章介绍了 typescript 类型体操中涉及到的基本概念,这篇文章我会将创建的utility Type进行实例讲解,并一一实现它。通过实践来深刻体会 , Utility Types 是一种特殊的类型,它们不是具体的值类型,而是可以对现有类型进行操作的类型。这些操作包括但不限于:选择属性、排除属性、从属性中提取类型等。

  • TypeScript体操(一):从基础到进阶

Just Do It!


在这里插入图片描述

正文开始如果觉得文章对您有帮助,请帮我三连+订阅,谢谢💖💖💖


常用 Utility Types 及其实现

TypeScript 提供了许多内置的 Utility Types, 下面我们只列举出了一些工作中常用的类型进行实现

Partial<T>

Partial<T> 将类型 T 的所有属性设置为可选。

  • 使用实例

    interface User {
      id: number;
      name: string;
      age: number;
    }
    
    const updateUser = (user: Partial<User>) => {
      // 可以只传递部分属性
      console.log(user);
    };
    
    updateUser({ name: "张三" });
    
  • 手写实现

    type MyPartial<T> = {
      [P in keyof T]?: T[P];
    };
    

Required<T>

Required<T> 将类型 T 的所有属性设置为必选。

  • 使用实例

    interface User {
      id: number;
      name: string;
      age: number;
    }
    
    const updateUser = (user: Required<User>) => {
      // 必须传递所有属性
      console.log(user);
    };
    
    updateUser({ id:1 , name: "张三", age:20 });
    
  • 手写实现

    type MyRequired<T> = {
      [P in keyof T]: T[P];
    };
    

Readonly<T>

Readonly<T> 使类型 T 的所有属性变为只读。

  • 使用实例

    interface User {
      id: number;
      name: string;
      age: number;
    }
    
    const user: Readonly<User> = {
      id: 1,
      name: "张三",
      age: 20,
    };
    
    // user.name = "李四"; // Error: name是自读属性, 不能进行赋值
    
  • 手写实现

    type MyReadonly<T> = {
      readonly [P in keyof T]: T[P];
    };
    

Pick<T, K>

Pick<T, K> 从类型 T 中选取部分属性,创建一个新的类型。

  • 使用实例

    interface User {
      id: number;
      name: string;
      age: number;
      email: string;
    }
    
    type UserNameAndEmail = Pick<User, "name" | "email">;
    
    const user: UserNameAndEmail = {
      name: "张三",
      email: "zhangsan@example.com",
    };
    
  • 手写实现

    type MyPick<T, K extends keyof T> = {
      [P in K]: T[P];
    };
    

Omit<T, K>

Omit<T, K> 从类型 T 中排除部分属性,创建一个新的类型。

  • 使用实例

    interface User {
      id: number;
      name: string;
      age: number;
      email: string;
    }
    
    type UserWithoutEmail = Omit<User, "email">;
    
    const user: UserWithoutEmail = {
      id: 1,
      name: "张三",
      age: 20,
    };
    
  • 手写实现

    type MyOmit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
    
    // 不依赖其他
    type MyOmit<T, K> = {
      [Key in keyof T as Key extends K ? never : Key]: T[Key]
    }
    

Record<K, T>

Record<K, T> 创建一个类型,其键为 K 类型,值为 T 类型的字典。

  • 使用实例

    type Role = "admin" | "user" | "guest";
    
    interface User {
      id: number;
      name: string;
    }
    
    const users: Record<Role, User> = {
      admin: { id: 1, name: "管理员" },
      user: { id: 2, name: "普通用户" },
      guest: { id: 3, name: "访客" },
    };
    
  • 手写实现

    type MyRecord<K extends keyof any, T> = {
      [P in K]: T;
    };
    

Exclude<T, U>

Exclude<T, U> 从类型 T 中排除类型 U 的所有属性。

  • 使用实例

    type T = "a" | "b" | "c";
    type U = "a";
    
    type Result = Exclude<T, U>; // "b" | "c"
    
  • 手写实现

    type MyExclude<T, U> = T extends U ? never : T;
    

Extract<T, U>

Extract<T, U> 从类型 T 中提取出类型 U 的所有属性。

  • 使用实例

    type T = "a" | "b" | "c";
    type U = "a" | "c";
    
    type Result = Extract<T, U>; // "a" | "c"
    
  • 手写实现

    type MyExtract<T, U> = T extends U ? T : never;
    

NonNullable<T>

NonNullable<T> 从类型 T 中排除 nullundefined

  • 使用实例

    type T = string | number | null | undefined;
    
    type Result = NonNullable<T>; // string | number
    
  • 手写实现

    type MyNonNullable<T> = T extends null | undefined ? never : T;
    

ReturnType<T>

ReturnType<T> 提取函数类型 T 的返回类型。

  • 使用实例

    function getUser(): { id: number; name: string } {
      return { id: 1, name: "张三" };
    }
    
    type User = ReturnType<typeof getUser>; // { id: number; name: string }
    
  • 手写实现

    type MyReturnType<T extends (...args: any) => any> = T extends (
      ...args: any
    ) => infer R
      ? R
      : any;
    

InstanceType<T>

InstanceType<T> 提取构造函数类型 T 的实例类型。

  • 使用实例

    class User {
      constructor(public id: number, public name: string) {}
    }
    
    type UserInstance = InstanceType<typeof User>; // User
    
  • 手写实现

    type MyInstanceType<T extends new (...args: any) => any> = T extends new (
      ...args: any
    ) => infer R
      ? R
      : any;
    

Parameters<T>

Parameters<T> 提取函数类型 T 的参数类型组成的元组。

  • 使用实例

    function createUser(name: string, age: number) {
      return { name, age };
    }
    
    type Params = Parameters<typeof createUser>; // [string, number]
    
  • 手写实现

    type MyParameters<T extends (...args: any) => any> = T extends (...args: infer P) => any
      ? P
      : never;
    

ConstructorParameters<T>

ConstructorParameters<T> 提取构造函数类型 T 的参数类型组成的元组。

  • 使用实例

    class User {
      constructor(public name: string, public age: number) {}
    }
    
    type Params = ConstructorParameters<typeof User>; // [string, number]
    
  • 手写实现

    type MyConstructorParameters<T extends new (...args: any) => any> = T extends new (
      ...args: infer P
    ) => any
      ? P
      : never;
    

Awaited<T>

该类型用于模拟 async 函数中的 await 操作,或者 promise 上的 .then() 方法,独特之处在于,它们通过递归展开 promise 的方式获取异步返回的结果。
如果 推断的类型 F 仍未函数类型,则继续递归 F extends (value: infer V) => any ? Awaited<V> : never

  • 使用实例

    type A = Awaited<Promise<string>>; // type A = string
    type B = Awaited<Promise<Promise<number>>>; // type B = number
    type C = Awaited<boolean | Promise<number>>; // type C = number | boolean
    
  • 手写实现

    type MyAwaited<T> = T extends null | undefined ? T : T extends object & {
        then(onfulfilled: infer F): any;
    } ? F extends (value: infer V) => any ? MyAwaited<V> : never : T
    
    type A = MyAwaited<Promise<string>>; // type A = string
    type B = MyAwaited<Promise<Promise<number>>>; // type B = number
    type C = MyAwaited<boolean | Promise<number>>; // type C = number | boolean
    
    

结语

通过这篇文章,我们深入探讨了 TypeScript 中的 Utility Types 及其实现和应用。这些类型工具在实际开发中非常有用,能够帮助我们简化代码、提高类型安全性和可维护性。掌握这些技巧,能让你在处理复杂类型时游刃有余。希望这些内容对你有所帮助,并激发你在 TypeScript 类型体操方面的更多探索和实践。

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

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

相关文章

yolo5图片视频、摄像头推理demo

yolo5图片、视频推理demo 图片 import torch# 加载预训练模型 model torch.hub.load(./yolo5, custom, pathyolov5s.pt, sourcelocal)# 加载图片 img 1.jpg# 进行推理 results model(img)# 解析结果 detections results.xyxy[0].cpu().numpy() # [x1, y1, x2, y2, confid…

Windows下载、安装、部署Redis服务的详细流程

本文介绍在Windows电脑中&#xff0c;下载、安装、部署并运行Redis数据库服务的方法。 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源、高性能的键值存储系统&#xff0c;最初由Salvatore Sanfilippo在2009年发布&#xff0c;并由Redis Labs维护。Redis因其…

【爱上C++】list用法详解、模拟实现

文章目录 一&#xff1a;list介绍以及使用1.list介绍2.基本用法①list构造方式②list迭代器的使用③容量④元素访问⑤插入和删除⑥其他操作image.png 3.list与vector对比 二&#xff1a;list模拟实现1.基本框架2.节点结构体模板3.__list_iterator 结构体模板①模板参数说明②构…

如何在Ubuntu上安装并启动SSH服务(Windows连接)

在日常的开发和管理工作中&#xff0c;通过SSH&#xff08;Secure Shell&#xff09;连接到远程服务器是一个非常常见的需求。如果你在尝试通过SSH连接到你的Ubuntu系统时遇到了问题&#xff0c;可能是因为SSH服务未安装或未正确配置。本文将介绍如何在Ubuntu上安装并启动SSH服…

气膜工业仓储与气膜体育馆的配置区别—轻空间

气膜工业仓储和气膜体育馆在配置上有明显的区别&#xff0c;这主要是由于它们的使用功能和环境不同所导致的。 结构设计 气膜工业仓储&#xff1a; 主要设计为大跨度、大空间&#xff0c;以便容纳大量货物。 气膜体育馆&#xff1a; 设计注重支撑观众席、运动场地和相关设施&…

安全与便捷并行,打造高效易用的用户支付体验

在当今数字时代&#xff0c;快捷、安全的支付方式已经成为用户日常生活中不可或缺的一部分。不论是在线购物、订阅服务&#xff0c;还是线下消费&#xff0c;用户都期望享受流畅且安全的支付体验。作为开发者&#xff0c;选择适合的支付服务不仅关乎用户体验&#xff0c;更直接…

android13禁用某个usb设备

总纲 android13 rom 开发总纲说明 目录 1.前言 2.触摸设备查看 3.功能修改 3.1 禁用usb触摸 3.2 禁用usb键盘 3.3 禁用usb遥感 4.查看生效与否 5.彩蛋 1.前言 用户想要禁止使用某些usb设备,需要系统不能使用相关的usb设备,例如usb触摸屏,usb键盘,usb遥感等等usb…

收银系统源码-线上商城diy装修

线下线上一体化收银系统越来越受门店重视&#xff0c;尤其是连锁多门店&#xff0c;想通过线下线上相互带动&#xff0c;相互引流&#xff0c;提升门店营业额。商城商城如何装修呢&#xff1f; 1.收银系统开发语言 核心开发语言: PHP、HTML5、Dart后台接口: PHP7.3后合管理网…

【系统架构设计 每日一问】四 如何对关系型数据库及NoSql数据库选型

根据不同的业务需求和场景&#xff0c;选择适合的数据库类型至关重要。以下是一个优化后的表格展示&#xff0c;涵盖了管理型系统、大流量系统、日志型系统、搜索型系统、事务型系统、离线计算和实时计算七大类业务系统的数据库选型建议。先明确下NoSQL的分类 NoSQL数据库分类…

微信小程序开发--点击圆圈小问号弹注解tip 点击其他区域关闭(组件 w-tip 弹框在小圆圈的 上下左右 可以自己控制 )

引言 在微信小程序开发中&#xff0c;实现用户交互的多样性是提升用户体验的关键之一。本文将详细介绍如何在微信小程序中实现点击圆圈小问号弹出注解&#xff08;Tip&#xff09;的功能。这种功能常见于帮助信息、提示说明等场景&#xff0c;能够为用户提供即时的帮助和反馈。…

昇思25天学习打卡营第17天|LLM-基于MindSpore的GPT2文本摘要

打卡 目录 打卡 环境准备 准备阶段 数据加载与预处理 BertTokenizer 部分输出 模型构建 gpt2模型结构输出 训练流程 部分输出 部分输出2&#xff08;减少训练数据&#xff09; 推理流程 环境准备 pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspo…

两个数组的dp问题

目录 最长公共子序列 不相交的线 不同的子序列 通配符匹配 正则表达式匹配 交错字符串 两个字符串的最小ASCII删除和 最长重复子数组 声明&#xff1a;接下来主要使用动态规划来解决问题&#xff01;&#xff01;&#xff01; 最长公共子序列 题目 思路 根据经验题目…

项目笔记| 基于Arduino和IR2101的无刷直流电机控制器

本文介绍如何使用 Arduino UNO 板构建无传感器无刷直流 &#xff08;BLDC&#xff09; 电机控制器或简单的 ESC&#xff08;电子速度控制器&#xff09;。 无刷直流电机有两种类型&#xff1a;有传感器和无传感器。有感无刷直流电机内置3个霍尔效应传感器&#xff0c;这些传感…

宝塔SSL续签失败

我有2个网站a和b&#xff08;文字中用baidu.com替换我的域名&#xff09; b是要续签那个&#xff0c;但续签报错&#xff1a; nginx version: nginx/1.22.1 nginx: [emerg] host not found in upstream "github.com" in /www/server/panel/vhost/nginx/proxy/a.bai…

【Redis进阶】事务

1. Redis与MySQL的事务差别 相信一谈到事务&#xff0c;大家马上就能联想到MySQL的事务&#xff0c;其事务具有ACID四大特性&#xff0c;但是Redis的事务相比较于MySQL&#xff0c;那就是个"弟中弟"&#xff0c;下面我们就来简单对比两者的事务特性&#xff1a; 原…

用神经网络求解微分方程

微分方程是物理科学的主角之一&#xff0c;在工程、生物、经济甚至社会科学中都有广泛的应用。粗略地说&#xff0c;它们告诉我们一个量如何随时间变化&#xff08;或其他参数&#xff0c;但通常我们对时间变化感兴趣&#xff09;。我们可以了解人口、股票价格&#xff0c;甚至…

【Java面向对象】二进制I/O

文章目录 1.二进制文件2.二进制 I/O 类2.1 FileInputStream 和 FileOutputStream2.2 FilterInputStream和 FilterOutputStream2.3 DatalnputStream 和 DataOutputStream2.4 BufferedInputStream 和 BufferedOutputStream2.5 ObjectInputStream 和 ObjectOutputStream 2.6 Seria…

深入理解 Linux Zero-copy 原理与实现策略图解

用户态和内核态 一般来说&#xff0c;我们在编写程序操作 Linux I/O 之时十有八九是在用户空间和内核空间之间传输数据&#xff0c;因此有必要先了解一下 Linux 的用户态和内核态的概念。 从宏观上来看&#xff0c;Linux 操作系统的体系架构分为用户态和内核态&#xff08;或者…

昇思25天学习打卡营第24天|ResNet50迁移学习

课程打卡凭证 迁移学习 迁移学习是机器学习中一个重要的技术&#xff0c;通过在一个任务上训练的模型来改善在另一个相关任务上的表现。在深度学习中&#xff0c;迁移学习通常涉及在一个大型数据集&#xff08;如ImageNet&#xff09;上预训练的模型上进行微调&#xff0c;以便…

设计模式之策略模式_入门

前言 最近接触了优惠券相关的业务&#xff0c;如果是以前&#xff0c;我第一时间想到的就是if_else开始套&#xff0c;这样的话耦合度太高了&#xff0c;如果后期添加或者删除优惠券&#xff0c;必须直接修改业务代码&#xff0c;不符合开闭原则&#xff0c;这时候就可以选择我…