【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. 总结

  • 分发逆变推断的核心作用
    • 结合分布式条件类型和逆变的行为,动态推断出参数或返回值的类型。
    • 支持灵活的类型操作,特别是在处理函数联合类型时。
  • 常见场景
    • 提取函数参数类型。
    • 处理多态函数。
  • 注意事项
    • 理解逆变对联合类型的影响(交集类型)。
    • 避免过度复杂化类型定义。
相关推荐
Struggler2811 分钟前
google插件开发:如何开启特定标签页的sidePanel
前端
爱编程的喵13 分钟前
深入理解JSX:从语法糖到React的魔法转换
前端·react.js
代码的余温22 分钟前
CSS3文本阴影特效全攻略
前端·css·css3
AlenLi32 分钟前
JavaScript - 策略模式在开发中的应用
前端
xptwop34 分钟前
05-ES6
前端·javascript·es6
每天开心35 分钟前
告别样式冲突:CSS 模块化实战
前端·css·代码规范
wxjlkh37 分钟前
powershell 批量测试ip 端口 脚本
java·服务器·前端
海底火旺38 分钟前
单页应用路由:从 Hash 到懒加载
前端·react.js·性能优化
每天开心38 分钟前
噜噜旅游App(3)——打造个性化用户中心:AI生成头像与交互设计
前端·前端框架
flashier39 分钟前
ESP32学习笔记_Components(1)——使用LED Strip组件点亮LED灯带
学习·esp32·led·led灯带·esp32组件