【TS学习】(18)分发逆变推断

在 TypeScript 中,分发逆变推断(Distributive and Contravariant Inference) 是一个相对高级且复杂的概念,涉及到分布式条件类型和逆变(Contravariance)的结合。理解这个概念需要对以下三个核心知识点有清晰的认识:

  1. 分布式条件类型(Distributive Conditional Types)
  2. 逆变(Contravariance)
  3. infer 关键字

1. 分布式条件类型

(1) 定义
  • 当条件类型作用于一个裸类型参数(Naked Type Parameter),并且该参数是一个联合类型时,TypeScript 会将条件类型"分布"到联合类型的每个成员上。
  • 这种行为称为分布式条件类型
(2) 示例
typescript 复制代码
type IsString<T> = T extends string ? true : false;

type Result = IsString<string | number>; // true | false

在这里:

  • string | number 被分发为 stringnumber
  • 条件类型分别应用于 stringnumber,最终结果是 true | false

2. 逆变(Contravariance)

(1) 定义
  • 逆变是指在函数参数中,子类型关系的方向与返回值相反。
  • 如果类型 A 是类型 B 的子类型,则函数 (arg: B) => void(arg: A) => void 的子类型。
(2) 示例
typescript 复制代码
type Func<T> = (arg: T) => void;

const anyFunc: Func<any> = (arg: any) => console.log(arg);
const stringFunc: Func<string> = anyFunc; // 合法:逆变

在这里:

  • 函数参数是逆变的,因此 Func<any>Func<string> 的子类型。

3. 分发逆变推断

当分布式条件类型与逆变结合时,可能会出现一些复杂的行为。这种现象被称为分发逆变推断

示例 1:函数参数的分布式条件类型
typescript 复制代码
type ParametersFromFunction<T> = T extends (arg: infer P) => any ? P : never;

type Func1 = ParametersFromFunction<(arg: string) => void>; // string
type Func2 = ParametersFromFunction<(arg: number) => void>; // number

type UnionFunc = ParametersFromFunction<((arg: string) => void) | ((arg: number) => void)>; // string & number

在这里:

  • ParametersFromFunction 使用 infer P 提取了函数参数的类型。
  • 对于单个函数类型,结果是参数类型本身(如 stringnumber)。
  • 对于联合类型 (arg: string) => void | (arg: number) => void,参数类型被推断为 string & number

这是因为:

  • 函数参数是逆变的,联合类型的逆变会导致参数类型变为所有可能类型的交集(string & number)。

示例 2:数组元素的分布式条件类型
typescript 复制代码
type ArrayElement<T> = T extends (infer E)[] ? E : never;

type Numbers = ArrayElement<number[]>; // number
type Strings = ArrayElement<string[]>; // string

type MixedArray = ArrayElement<(string | number)[]>; // string | number

在这里:

  • 数组元素是协变的,因此联合类型的分发结果是 string | number

4. 实际应用场景

(1) 提取函数参数类型

你可以使用分布式条件类型和逆变推断提取函数参数的类型。

示例代码
typescript 复制代码
type ParametersFromFunction<T> = T extends (arg: infer P) => any ? P : never;

type FuncUnion = ParametersFromFunction<((arg: string) => void) | ((arg: number) => void)>; // string & number

在这里:

  • 函数参数的逆变导致联合类型的推断结果是交集类型(string & number)。

(2) 处理多态函数

你可以使用分发逆变推断来处理多态函数的参数类型。

示例代码
typescript 复制代码
type Func<T> = (arg: T) => void;

type InferParameters<T> = T extends Func<infer P> ? P : never;

type Result = InferParameters<Func<string> | Func<number>>; // string & number

在这里:

  • InferParameters 使用 infer P 提取了函数参数的类型。
  • 因为函数参数是逆变的,联合类型的推断结果是交集类型(string & number)。

5. 注意事项

(1) 交集类型的意义
  • 在逆变推断中,联合类型的参数会被推断为交集类型。
  • 这是因为逆变要求参数类型必须兼容所有可能的情况。
示例
typescript 复制代码
type FuncUnion = ((arg: string) => void) | ((arg: number) => void);

type Parameters = ParametersFromFunction<FuncUnion>; // string & number

在这里:

  • 参数类型 string & number 表示函数可以接受同时兼容 stringnumber 的值(即 never)。

(2) 避免过度复杂
  • 分发逆变推断的结果可能会导致交集类型变得难以理解。
  • 在实际开发中,尽量避免过于复杂的类型操作。

6. 总结

  • 分发逆变推断的核心作用
    • 结合分布式条件类型和逆变的行为,动态推断出参数或返回值的类型。
    • 支持灵活的类型操作,特别是在处理函数联合类型时。
  • 常见场景
    • 提取函数参数类型。
    • 处理多态函数。
  • 注意事项
    • 理解逆变对联合类型的影响(交集类型)。
    • 避免过度复杂化类型定义。
相关推荐
超哥--6 小时前
B站视频内容智能分析系统(九):React 前端与管理面板
前端·react.js·前端框架
V搜xhliang02467 小时前
AI智能体的数据安全与合规实践
人工智能·学习·数据分析·自动化·ai编程
无敌的牛8 小时前
redis学习过程
数据库·redis·学习
Cutecat_9 小时前
视频字幕处理工具横向:提取模式 vs 编辑模式,该如何选择
android·前端·ios·语音识别
qq_422152579 小时前
PDF 加水印工具怎么选?2026 年文档版权保护方案对比
前端·pdf·github
kyriewen9 小时前
手写 Promise.all、race、any:不到 30 行代码,解决并发异步的所有姿势
前端·javascript·面试
brucelee18610 小时前
OpenClaw 浏览器控制(Chrome MCP)完整教程
前端·chrome
ct97810 小时前
React 状态管理方案深度对比
开发语言·前端·react
旅僧10 小时前
Π环境部署(运行 且 无理论讲解)
学习
jushi899910 小时前
Lucas Chess R国际象棋、中国象棋、日本将棋、五子棋训练学习工具游戏软件
学习