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

目录

    • 前言
    • 常用 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 类型体操方面的更多探索和实践。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

synergy配置

今天介绍一个电脑同步软件synergy。 我们开发时一般会用两套设备&#xff0c;如果使用两套键盘操作起来会很麻烦&#xff0c;这个软件就是解决这个问题&#xff0c;可以使用一套键盘同时操作两台电脑&#xff0c;另一台作为客户端被控制。 安装 在两台电脑上各自下载安装syne…

沃文特过会两年仍在注册:营收净利润下滑,三次抽查不合格

《港湾商业观察》施子夫 王璐 在当前IPO严查之际&#xff0c;部分企业的上市进程可谓相当漫长&#xff0c;四川沃文特生物工程股份有限公司&#xff08;以下简称&#xff0c;沃文特&#xff09;就是其中之一。 不过&#xff0c;最近的好消息是&#xff0c;沃文特又更新了招股…

NVIDIA Container Toolkit 安装与配置帮助文档(Ubuntu,Docker)

NVIDIA Container Toolkit 安装与配置帮助文档(Ubuntu,Docker) 本文档详细介绍了在 Ubuntu Server 22.04 上使用 Docker 安装和配置 NVIDIA Container Toolkit 的过程。 概述 NVIDIA 容器工具包使用户能够构建和运行 GPU 加速容器。即可以在容器中使用NVIDIA显卡。 架构图如…

【BUG】已解决:TypeError: Descriptors cannot not be created directly.

已解决&#xff1a;TypeError: Descriptors cannot not be created directly. 目录 已解决&#xff1a;TypeError: Descriptors cannot not be created directly. 【常见模块错误】 【错误原因】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来…

谷粒商城实战笔记-46-商品服务-API-三级分类-配置网关路由与路径重写

文章目录 一&#xff0c;准备工作1&#xff0c;新增一级菜单2&#xff0c;新增二级菜单 二&#xff0c;前端树形界面开发1&#xff0c;开发分类展示组件 本节的主要内容&#xff1a; 前端调用三级分类接口&#xff0c;并树形展示 一&#xff0c;准备工作 启动product服务启动…

【开源库学习】libodb库学习(三)

4 查询数据库 如果我们不知道我们正在寻找的对象的标识符&#xff0c;我们可以使用查询在数据库中搜索符合特定条件的对象。ODB查询功能是可选的&#xff0c;我们需要使用--generate-query ODB编译器选项显式请求生成必要的数据库支持代码。 ODB提供了一个灵活的查询API&#x…

RPM、YUM 安装 xtrabackup 8 (mysql 热备系列一)包含rpm安装 mysql 8 配置主从

RPM安装 percona-xtrabackup-80-8.0.35-30.1.el7.x86_64.rpm 官网&#xff1a; https://www.percona.com/ 下载地址&#xff1a; https://www.percona.com/downloads wget https://downloads.percona.com/downloads/percona-distribution-mysql-ps/percona-distribution-mysq…

接口测试JMeter-1.接口测试初识

第一章 接口测试初识 1. 接口测试理论基础 “接口测试”一个让人觉得非常高大上的名词&#xff0c;特别是对于刚入门的测试同学而言。随着测试技术不断的深化&#xff0c;“接口测试”出现在我们视野中的频次越来越高。那么接口测试到底是如何做的&#xff1f;接口测试的优势又…

《简历宝典》17 - 简历中“技术能力”,如何丰满且有层次,前端篇

这一节开始对技术能力模块做讲解&#xff0c;我们身边的这些互联网IT从业者们&#xff0c;前端开发、Java开发、软件测试又或者是其他职位的开发者们&#xff0c;技术能力这个模块是绕不过去的&#xff0c;从简历上看&#xff0c;这个模块体现了我们之前软件工作生涯中的技术功…

解决:Linux上SVN 1.12版本以上无法直接存储明文密码

问题&#xff1a;今天在Linux机器上安装了SVN&#xff0c;作为客户端使用&#xff0c;首次执行SVN相关操作&#xff0c;输入账号密码信息后&#xff0c;后面再执行SVN相关操作&#xff08;比如"svn update"&#xff09;还是每次都需要输入密码。 回想以前在首次输入…

跨平台WPF音乐商店应用程序

目录 一 简介 二 设计思路 三 源码 一 简介 支持在线检索音乐&#xff0c;支持实时浏览当前收藏的音乐及音乐数据的持久化。 二 设计思路 采用MVVM架构&#xff0c;前后端分离&#xff0c;子界面弹出始终位于主界面的中心。 三 源码 视窗引导启动源码&#xff1a; namesp…

Web开发:ASP.NET CORE前后端交互之AJAX(含基础Demo)

目录 一、后端 二、前端 三、代码位置 四、实现效果 五、关键的点 1.后端传输给前端&#xff1a; 2.前端传输给后端 一、后端 using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.Rendering; using WebAppl…

JavaWeb服务器-Tomcat(Tomcat概述、Tomcat的下载、安装与卸载、启动与关闭、常见的问题)

Tomcat概述 Tomcat服务器软件是一个免费的开源的web应用服务器。是Apache软件基金会的一个核心项目。由Apache&#xff0c;Sun和其他一些公司及个人共同开发而成。 由于Tomcat只支持Servlet/JSP少量JavaEE规范&#xff0c;所以是一个开源免费的轻量级Web服务器。 JavaEE规范&…

Unity XR Interaction Toolkit的安装(二)

提示&#xff1a;文章有错误的地方&#xff0c;还望诸位大神不吝指教&#xff01; 文章目录 前言一、安装1.打开unity项目2.打开包管理器&#xff08;PackageManage&#xff09;3.导入Input System依赖包4.Interaction Layers unity设置总结 前言 安装前请注意&#xff1a;需要…

通过vue3 + TypeScript + uniapp + uni-ui 实现下拉刷新和加载更多的功能

效果图: 核心代码: <script lang="ts" setup>import { ref, reactive } from vue;import api from @/request/api.jsimport empty from @/component/empty.vueimport { onLoad,onShow, onPullDownRefresh, onReachBottom } from @dcloudio/uni-applet form …

大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; HadoopHDFSMapReduceHiveFlumeSqoopZookeeperHBaseRedis 章节内容 上一节我们完成了&#xff1a; HBase …

Python面试宝典第16题:跳跃游戏

题目 给你一个非负整数数组 nums &#xff0c;你最初位于数组的第一个下标 &#xff0c;数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true。否则&#xff0c;返回 false。 示例 1&#xff1a; 输…

Shell程序设计

各位看官&#xff0c;从今天开始&#xff0c;我们进入新的专栏Shell学习&#xff0c;Shell 是操作系统的命令行界面&#xff0c;它允许用户通过输入命令与操作系统交互。常见的 Shell 有 Bash 和 Zsh&#xff0c;它们可以执行用户输入的命令或运行脚本文件。Shell 广泛应用于系…

【PostgreSQL】PostgreSQL 教程

博主介绍&#xff1a;✌全网粉丝20W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…

第一百七十四节 Java IO教程 - Java字符集

Java IO教程 - Java字符集 我们可以使用编码方案将Unicode字符转换为字节序列&#xff0c;反之亦然。 java.nio.charset包提供了将CharBuffer编码/解码为ByteBuffer的类&#xff0c;反之亦然。 Charset类的对象表示编码方案。 CharsetEncoder类执行编码。 CharsetDecoder类执…