TypeScript泛型约束与条件类型:看完就懂

2026-03-29 0 959

核心结论:何时用泛型约束?何时用条件类型

泛型约束()用于限制泛型参数的类型范围,让你能安全地访问参数的特定属性;条件类型(T U ? X : Y)用于根据输入类型动态计算输出类型。两者都依赖 关键字,但作用完全不同。

一句话区分

泛型约束:“这个泛型必须满足什么条件”(定义阶段限制)

条件类型:“如果这个类型满足条件,结果是什么类型”(计算阶段分支)

一、泛型约束( )

1.1 是什么?

泛型约束通过 关键字限定泛型参数必须包含某些属性或方法,从而让函数/类内部可以安全地使用这些成员。

1.2 基本语法

 <T  { :  }>(arg: T): T {
  .log(arg.); // ✅ 安全,因为T一定有属性
   arg;
}

1.3 常见使用场景

| 场景 | 示例约束 | 作用 |

|——|———|——|

| 限制必须有属性 | T { : } | 处理字符串、数组等 |

| 限制必须为对象类型 | T | 排除原始类型 |

| 限制必须实现某个接口 | T HasId | 确保有id字段 |

| 限制必须为特定类型的子类型 | T | | 联合类型约束 |

1.4 完整代码示例

  {
  name: ;
}
 greet<T  >(obj: T):  {
   Hello, ${obj.name}; // ✅ T一定有name属性
}
greet({ name: 'Alice', age: 30 }); // ✅ 可以传入额外属性
// greet({ age: 20 }); // ❌ 错误:缺少name属性

1.5 多重约束(使用接口交叉)

 merge<T  , U  >(a: T, b: U): T & U {
   { ...a, ...b };
}

二、条件类型( Types)

2.1 是什么?

条件类型根据类型关系T U ? X : Y类型层面做分支判断,用于动态生成不同类型的定义。

2.2 基本语法

type <T> = T   ? true : false;
type A = <'hello'>; // true
type B = <>;  // false

2.3 常见使用场景

| 场景 | 示例 | 说明 |

|——|——|——|

| 过滤联合类型中的某些成员 | type <T> = T ? T : never | 保留类型 |

| 提取函数返回值类型 | type <T> = T (...args: any[]) => infer R ? R : never | 配合infer |

| 类型映射中的条件分支 | type <T> = T null | ? T : T | null | 条件添加null |

| 递归类型处理 | type <T> = { [P in keyof T]: <T[P]> } | 结合条件判断 |

2.4 配合infer提取类型

type <T> = T  (infer U)[] ? U : never;
type Item1 = <[]>; // 
type Item2 = <>;   // never(因为不是数组)

2.5 分布式条件类型

泛型约束与条件类型

T是联合类型时,条件类型会自动分发到每个成员:

type <T> = T  any ? T[] : never;
type  = < | >; // [] | []
// 等价于 (  any ? [] : never) | (  any ? [] : never)

注意:要关闭分发行为,可用元组包裹T

type <T> = [T]  [any] ? T[] : never;
type  = < | >; // ( | )[]

三、对比速查表

维度 泛型约束 条件类型
使用位置 泛型声明处(<T ...> 类型别名、接口、工具类型内部
关键字 (限制) ? :(判断)
作用阶段 类型参数传入时检查是否满足 类型计算时选择结果分支
能否改变输出类型 不能,只做限制 能,动态生成新类型
典型错误 试图约束字面量联合类型 忘记分布式条件类型的行为
常见伙伴 keyof、接口 infernever、递归

四、高频疑难解答

Q1:为什么我不能这样写约束?

// ❌ 错误:不能约束字面量值
 test<T  'a' | 'b'>(val: T) {}
// 这样写虽然语法正确,但只能传入'a'或'b',失去了泛型的灵活性

正确做法:如果需要限制值范围,使用联合类型本身,而非泛型约束。

Q2:条件类型中的never有什么用?

never在条件类型中常用来过滤类型

type <T> = T  null |  ? never : T;
type  = < | null | >; // 

Q3:泛型约束和条件类型可以一起用吗?

可以,且非常常见:

 pick<T  , K  keyof T>(obj: T, keys: K[]): Pick<T, K> {
  // 约束T为对象,K为T的键,然后通过条件类型(Pick内置)计算结果类型
  const  = {} as Pick<T, K>;
  keys.(key => [key] = obj[key]);
   ;
}

Q4:如何判断当前应该用约束还是条件类型?

约束:你想“限制能传什么类型”,让函数内部能安全使用某些属性。

条件类型:你想“根据输入类型返回不同的输出类型”,比如实现类型版的if-else

五、实战练习

请尝试推断以下代码的输出类型:

type <T> = T   ? never : T;
type  = <'a' | 123 | true>; // ?
type <T> = T  <infer V> ? V : T;
type  = <<>>; // ?
type <T  > = T;
type  = <42>; // ?

参考答案

= 123 | true(过滤掉)

= (提取内部的类型)

= 42(字面量类型)

六、官方标准参考

:泛型约束(

:条件类型( Types

发行说明:infer关键字(2.8版本)

以上语法与行为与 5.x版本完全一致。实际开发中请确保.json模式开启,以获得最准确的类型推断。

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

七爪网 行业资讯 TypeScript泛型约束与条件类型:看完就懂 https://www.7claw.com/2827155.html

七爪网源码交易平台

相关文章