千家信息网

TypeScript中条件类型精读与实践记录是怎样的

发表于:2025-11-13 作者:千家信息网编辑
千家信息网最后更新 2025年11月13日,本篇文章为大家展示了TypeScript中条件类型精读与实践记录是怎样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。在大多数程序中,我们必须根据输入做出决策
千家信息网最后更新 2025年11月13日TypeScript中条件类型精读与实践记录是怎样的

本篇文章为大家展示了TypeScript中条件类型精读与实践记录是怎样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

    在大多数程序中,我们必须根据输入做出决策。TypeScript 也不例外,使用条件类型可以描述输入类型与输出类型之间的关系。

    用于条件判断时的 extends

    当 extends 用于表示条件判断时,可以总结出以下规律

    若位于 extends 两侧的类型相同,则 extends 在语义上可理解为 ===,可以参考如下例子:

    type result1 = 'a' extends 'abc' ? true : false // falsetype result2 = 123 extends 1 ? true : false     // false

    若位于 extends 右侧的类型包含位于 extends 左侧的类型(即狭窄类型 extends 宽泛类型)时,结果为 true,反之为 false。可以参考如下例子:

    type result3 = string extends string | number ? true : false // true

    当 extends 作用于对象时,若在对象中指定的 key 越多,则其类型定义的范围越狭窄。可以参考如下例子:

    type result4 = { a: true, b: false } extends { a: true } ? true : false // true

    在泛型类型中使用条件类型

    考虑如下 Demo 类型定义:

    type Demo = T extends U ? never : T

    结合用于条件判断时的 extends,可知 'a' | 'b' | 'c' extends 'a' 是 false, 因此 Demo<'a' | 'b' | 'c', 'a'> 结果是 'a' | 'b' | 'c' 么?
    查阅官网,其中有提到:

    When conditional types act on a generic type, they become distributive when given a union type.

    即当条件类型作用于泛型类型时,联合类型会被拆分使用。即 Demo<'a' | 'b' | 'c', 'a'> 会被拆分为 'a' extends 'a'、'b' extends 'a'、'c' extends 'a'。用伪代码表示类似于:

    function Demo(T, U) {  return T.map(val => {    if (val !== U) return val    return 'never'  })}Demo(['a', 'b', 'c'], 'a') // ['never', 'b', 'c']

    此外根据 never 类型的定义 -- never 类型可分配给每种类型,但是没有类型可以分配给 never(除了 never 本身)。即 never | 'b' | 'c' 等价于 'b' | 'c'。

    因此 Demo<'a' | 'b' | 'c', 'a'> 的结果并不是 'a' | 'b' | 'c' 而是 'b' | 'c'。

    工具类型

    心细的读者可能已经发现了 Demo 类型的声明过程其实就是 TypeScript 官方提供的工具类型中 Exclude 的实现原理,其用于将联合类型 ExcludedUnion 排除在 Type 类型之外。

    type T = Demo<'a' | 'b' | 'c', 'a'> // T: 'b' | 'c'

    基于 Demo 类型定义,进一步地还可以实现官方工具类型中的 Omit,其用于移除对象 Type
    中满足 keys 类型的属性值。

    type Omit = {  [P in Demo]: Type

    }interface Todo { title: string; description: string; completed: boolean;}type T = Omit // T: { title: string; completed: boolean }

    逃离舱

    如果想让 Demo<'a' | 'b' | 'c', 'a'> 的结果为 'a' | 'b' | 'c' 是否可以实现呢? 根据官网描述:

    Typically, distributivity is the desired behavior. To avoid that behavior, you can surround each side of the extends keyword with square brackets.

    如果不想遍历泛型中的每一个类型,可以用方括号将泛型给括起来以表示使用该泛型的整体部分。
    type Demo = [T] extends [U] ? never : T

    type Demo = [T] extends [U] ? never : T// result 此时类型为 'a' | 'b' | 'c'type result = Demo<'a' | 'b' | 'c', 'a'>

    在箭头函数中使用条件类型

    在箭头函数中使用三元表达式时,从左向右的阅读习惯导致函数内容区若不加括号则会让使用方感到困惑。比如下方代码中 x 是函数类型还是布尔类型呢?

    // The intent is not clear.var x = a => 1 ? true : false

    在 eslint 规则 no-confusing-arrow 中,推荐如下写法:

    var x = a => (1 ? true : false)

    在 TypeScript 的类型定义中,若在箭头函数中使用 extends 也是同理,由于从左向右的阅读习惯,也会导致阅读者对类型代码的执行顺序感到困惑。

    type Curry

    = (arg: Head

    ) => HasTail

    extends true ? Curry, R> : R

    因此在箭头函数中使用 extends 建议加上括号,对于进行 code review 有很大的帮助。

    type Curry

    = (arg: Head

    ) => (HasTail

    extends true ? Curry, R> : R)

    结合类型推导使用条件类型

    在 TypeScript 中,一般会结合 extends 来使用类型推导 infer 语法。使用它可以实现自动推导类型的目的。比如用其来实现工具类型 ReturnType ,该工具类型用于返回函数 Type 的返回类型。
    type ReturnType = T extends (...args: any) => infer U ? U : never

    type ReturnType = T extends (...args: any) => infer U ? U : neverMyReturnType<() => string>          // stringMyReturnType<() => Promise // Promise

    结合 extends 与类型推导还可以实现与数组相关的 Pop、Shift、Reverse 工具类型。

    Pop:

    type Pop = T extends [...infer ExceptLast, any] ? ExceptLast : nevertype T = Pop<[3, 2, 1]> // T: [3, 2]

    Shift:

    type Shift = T extends [infer _, ...infer O] ? O : nevertype T = Shift<[3, 2, 1]> // T: [2, 1]

    Reverse

    type Reverse = T extends [infer F, ...infer Others]  ? [...Reverse, F]  : []type T = Reverse<['a', 'b']> // T: ['b', 'a']

    使用条件类型来判断两个类型完全相等

    我们也可以使用条件类型来判断 A、B 两个类型是否完全相等。当前社区上主要有两种方案:

    方案一: 参考 issue。

    export type Equal1 =  [T] extends [S] ? (    [S] extends [T] ? true : false  ) : false

    目前该方案的唯一缺点是会将 any 类型与其它任何类型判为相等。

    type T = Equal1<{x:any}, {x:number}> // T: true

    方案二: 参考 issue。

    export type Equal2 =  (() => T extends X ? 1 : 2) extends  (() => U extends Y ? 1 : 2) ? true : false

    目前该方案的唯一缺点是在对交叉类型的处理上有一点瑕疵。

    type T = Equal2<{x:1} & {y:2}, {x:1, y:2}> // false

    以上两种判断类型相等的方法见仁见智,笔者在此抛砖引玉。

    上述内容就是TypeScript中条件类型精读与实践记录是怎样的,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注行业资讯频道。

    类型 条件 函数 工具 方案 参考 箭头 结果 代码 例子 内容 对象 中条 实践 困惑 狭窄 两个 作用 官方 就是 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络安全幼儿园大班教案ppt 内乡第三小学开展网络安全教育 web服务器上创建虚拟机的方法 主机数据库名称密码怎么填 软件开发测试 职业规划 奇安信网络安全部 .net绑定数据库 动态配置不同数据库数据源 陕西戴尔服务器虚拟化多少钱 怎么开发手机小软件开发 中国科技技术期刊数据库 se无法连接数据库 计算机网络技术在就业方面 怎么看原神是什么服务器 数据库怎么还原为上一份数据 虹口区常规网络技术服务参考价格 第9讲网络安全协议与网络应用 网络安全及舆论 电脑qq服务器拒绝了你发送文件 oem 数据库 数据库考试题桂林理工大学 江阴智能软件开发市场价格 软件开发 人员培训 租服务器的要求 gis数据库的建立与入库 天津服务器定制公司 数据库汉字用双引号还是单引号 qq泄露密码数据库 棋牌游戏软件开发有限公司 服务器虚拟化用什么cpu最好
    0