Typescript高级: 深入理解infer关键字

2024-06-02 04:52

本文主要是介绍Typescript高级: 深入理解infer关键字,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

  • 在 TS 中,infer 是一个高级类型操作,特别是条件类型和映射类型中非常有用的关键字
  • 它在泛型中使用也会是一个强大工具,增强了类型推断的能力,让开发者更灵活地处理和操作类型
  • 它允许在泛型类型推导过程中捕获一个具体的类型,这对于编写复杂的类型转换和映射操作特别有用
  • infer 的定义
    • infer 表示在 extends 条件语句中以占位符出现的用来修饰数据类型的关键字
    • 被修饰的数据类型等到使用时才能被推断出来
  • infer 占位符式的关键字出现的位置
    • infer 出现在 extends 条件语句后的函数类型的参数类型位置上
    • infer 出现在 extends 条件语句后的函数类型的返回值类型上
    • infer 出现在类型的泛型具体化类型上

实现

1 )infer 出现在 extends 条件语句后的函数类型的参数类型位置上

// 定义了一个接口Customer,它描述了一个具有name(字符串类型)和moneyPaid(数字类型)属性的对象
interface Customer {name: stringmoneyPaid: number
}// 定义了一个函数类型,接受一个Customer类型的参数并返回一个字符串
type custFuncType = (cust: Customer) => string// 定义了一个泛型类型inferType<T>,这是理解的重点。这是一个条件类型,它使用了infer关键字
type inferType<T> = T extends (params: infer P) => any ? P : T// 定义了inferResultType类型别名,它是通过将前面定义的custFuncType类型作为参数传递给inferType得到的
type inferResultType = inferType<custFuncType>
  • 分析一下这行代码:type inferType<T> = T extends (params: infer P) => any ? P : T
    • T extends (params: infer P) => any
      • 这部分是一个类型测试,检查T是否可以赋值给一个函数类型
      • 该函数接受一个参数(我们称之为params)
      • infer P关键字在这里用于声明一个新的类型变量P,用来捕获T中函数参数的实际类型
    • ? P
      • 如果上面的测试为真(即T确实是一个函数类型)
      • 那么整个条件类型的结果就是捕获的参数类型P
    • : T
      • 如果上面的测试为假(即T不是函数类型或不匹配)
      • 则条件类型的结果就是T本身,不做任何改变
  • 最后一行代码 type inferResultType = inferType<custFuncType>
    • custFuncType是一个接受Customer类型参数的函数,所以infer P会捕获到这个参数类型
    • 因此,inferResultType 实际上就是Customer类型

2 ) infer 出现在 extends 条件语句后的函数类型的返回值类型上

// 定义了一个接口Customer,它描述了一个具有name(字符串类型)和moneyPaid(数字类型)属性的对象
interface Customer {custname: stringmoneyPaid: number
}
// 这个类型定义了一个函数,该函数接受一个Customer类型的参数并返回一个字符串
type custFuncType = (cust: Customer) => string
type inferType<T> = T extends (params: any) => infer P ? P : T
type inferResultType = inferType<custFuncType>
  • 核心在这里, type inferType<T> = T extends (params: any) => infer P ? P : T
    • 上面,inferType 的 infer 在返回值的位置上
    • infer P 表示“推断出一个类型 P”,这个 P 是函数的返回类型
    • 它根据 extends 的检查结果来选择不同的类型
    • 如果 T 是一个符合 (params: any) => … 形式的函数类型
    • 那么表达式的结果是 P(即函数的返回类型)
    • 否则,表达式的结果是 T 本身
  • 最后,type inferResultType = inferType<custFuncType>
    • 由于,custFuncType 是一个返回值为 string 的函数类型
    • 符合,inferType 内部的三元推导的条件,因为 返回值是 P, 而在这里P又是 string 类型
    • 所以,type inferResultType 就是 string 类型

3 ) infer 出现在类型的泛型具体化类型上

class Subject {constructor(public id: number, public name: string) {}
}const chineseSubject = new Subject(100, "语文");
const mathSubject = new Subject(101, "数学");type ElementOfSet<T> = T extends Set<infer E> ? E : never;const subjectsSet = new Set<Subject>([chineseSubject, mathSubject]);type SubjectType = ElementOfSet<typeof subjectsSet>;// 使用推断出的SubjectType类型
function printSubject(subject: SubjectType) {console.log(`学科ID: ${subject.id}, 学科名称: ${subject.name}`);
}printSubject(chineseSubject);
  • 核心代码在这里:type ElementOfSet<T> = T extends Set<infer E> ? E : never;
    • 如果 参数 T 属于 Set 类型,则 ElementOfSet 则是 E 的类型
    • 这里 Set<infer E> 使用 infer E 推导出 E的类型,如果符合 extends 条件,则返回E,否则返回 never
  • const subjectsSet = new Set<Subject>([chineseSubject, mathSubject]);
    • 这里 subjectsSet 是一个 Set 类型,而且单个元素是 Subject 类型
  • type SubjectType = ElementOfSet<typeof subjectsSet>;
    • ElementOfSet<typeof subjectsSet> 这里符合内部条件,所以,它最终是一个 Subject 类型
  • 所以,在最后,printSubject 中完美运行

总结

  • infer关键字在TypeScript中为泛型编程提供了一个强大的工具
  • 它不仅增强了类型系统的表达能力,还使开发者能够编写出更加灵活和精确的类型定义
  • 通过掌握infer的使用,你能够在处理复杂类型逻辑和类型转换时更加游刃有余
  • 提升代码的类型安全性和可维护性

这篇关于Typescript高级: 深入理解infer关键字的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1023071

相关文章

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

Java中的for循环高级用法

《Java中的for循环高级用法》本文系统解析Java中传统、增强型for循环、StreamAPI及并行流的实现原理与性能差异,并通过大量代码示例展示实际开发中的最佳实践,感兴趣的朋友一起看看吧... 目录前言一、基础篇:传统for循环1.1 标准语法结构1.2 典型应用场景二、进阶篇:增强型for循环2.

使用Python进行GRPC和Dubbo协议的高级测试

《使用Python进行GRPC和Dubbo协议的高级测试》GRPC(GoogleRemoteProcedureCall)是一种高性能、开源的远程过程调用(RPC)框架,Dubbo是一种高性能的分布式服... 目录01 GRPC测试安装gRPC编写.proto文件实现服务02 Dubbo测试1. 安装Dubb

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

深入解析 Java Future 类及代码示例

《深入解析JavaFuture类及代码示例》JavaFuture是java.util.concurrent包中用于表示异步计算结果的核心接口,下面给大家介绍JavaFuture类及实例代码,感兴... 目录一、Future 类概述二、核心工作机制代码示例执行流程2. 状态机模型3. 核心方法解析行为总结:三

Apache 高级配置实战之从连接保持到日志分析的完整指南

《Apache高级配置实战之从连接保持到日志分析的完整指南》本文带你从连接保持优化开始,一路走到访问控制和日志管理,最后用AWStats来分析网站数据,对Apache配置日志分析相关知识感兴趣的朋友... 目录Apache 高级配置实战:从连接保持到日志分析的完整指南前言 一、Apache 连接保持 - 性

Java 关键字transient与注解@Transient的区别用途解析

《Java关键字transient与注解@Transient的区别用途解析》在Java中,transient是一个关键字,用于声明一个字段不会被序列化,这篇文章给大家介绍了Java关键字transi... 在Java中,transient 是一个关键字,用于声明一个字段不会被序列化。当一个对象被序列化时,被