ts 类型体操是指什么,给出各种示例
Search
TypeScript 类型体操 应用场景 30 results
“TypeScript 类型体操”是指利用 TypeScript 强大的类型系统,通过条件类型、映射类型、递归、模板字面量类型、infer 关键字等高级特性,对类型进行复杂变换与推导的技术。
它就像“类型世界里的函数式编程”——输入一个类型,输出一个新的类型,常用于:
- 从已有类型派生新类型(如 Omit、Pick、Partial)
- 实现类型级别的逻辑(如判断是否为联合类型)
- 模拟运行时行为(如字符串处理、数组操作)
✅ 经典类型体操示例(含实现)
1. 获取数组最后一个元素类型
TypeScript
Copy
type Last<T extends readonly any[]> = T extends [...any[], infer L] ? L : never;
type A = Last<[1, 2, 3]>; // 32. 首字母大写
TypeScript
Copy
type Capitalize<S extends string> =
S extends `${infer F}${infer R}` ? `${Uppercase<F>}${R}` : S;
type B = Capitalize<'hello'>; // 'Hello'3. 深层次的 Readonly(递归)
TypeScript
Copy
type IsPlainObject<T> = T extends (...args: any[]) => any
? false
: T extends object
? true
: false;
type DeepReadonly<T> = {
readonly [K in keyof T]: IsPlainObject<T[K]> extends true
? DeepReadonly<T[K]>
: T[K];
};
type C = DeepReadonly<{ a: { b: { c: string } } }>;
// { readonly a: { readonly b: { readonly c: string } } }4. 合并两个对象(冲突时以后者为准)
TypeScript
Copy
type Merge<F, S> = {
[K in keyof F | keyof S]: K extends keyof S
? S[K]
: K extends keyof F
? F[K]
: never;
};
type D = Merge<{ a: string; b: string }, { b: number; c: boolean }>;
// { a: string; b: number; c: boolean }5. 判断是否为联合类型
TypeScript
Copy
type IsUnion<T, U = T> = T extends any
? [U] extends [T]
? false
: true
: never;
type E = IsUnion<string | number>; // true
type F = IsUnion<string>; // false6. 字符串模板替换
TypeScript
Copy
type Replace<S, From extends string, To extends string> =
S extends `${infer L}${From}${infer R}` ? `${L}${To}${R}` : S;
type G = Replace<'hello world', 'world', 'ts'>; // 'hello ts'7. 获取构造函数实例类型
TypeScript
Copy
type Instance<T extends new (...args: any[]) => any> =
T extends new (...args: any[]) => infer R ? R : never;
class Person {}
type H = Instance<typeof Person>; // Person🎯 总结一句话
类型体操就是用 TS 的类型系统写“类型级别的函数”,实现类型计算、推导与验证的高级技巧。
如果你想练习,推荐:
需要我帮你拆解某个类型体操的实现过程吗?
下面按顺序拆解 示例 3 ~ 5 的实现过程,逐行解释它们到底在做什么、为什么这样写。
✅ 示例 3:深层次的 Readonly(递归)
TypeScript
Copy
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends (...args: any[]) => any
? T[K] // 函数类型不递归
: T[K] extends object
? DeepReadonly<T[K]> // 对象类型递归
: T[K]; // 原始类型直接返回
};🔍 拆解过程
[K in keyof T]:遍历T的所有键。- 第一层
extends (...args: any[]) => any:判断是否是函数,函数不递归(因为函数是引用类型,递归 readonly 无意义)。 - 第二层
extends object:判断是否是对象(排除原始类型如string、number)。- 如果是对象,递归调用
DeepReadonly<T[K]>。 - 否则直接返回
T[K](原始类型)。
readonly:给所有属性加上readonly修饰符。
✅ 示例 4:合并两个对象(冲突时以后者为准)
TypeScript
Copy
type Merge<F, S> = {
[K in keyof F | keyof S]: K extends keyof S
? S[K] // 如果 S 有 K,取 S[K]
: K extends keyof F
? F[K] // 如果 F 有 K 但 S 没有,取 F[K]
: never; // 兜底(理论上不会触发)
};🔍 拆解过程
keyof F | keyof S:联合两个对象的所有键。- 条件分发:
- 如果
K是S的键,优先取S[K](覆盖)。 - 否则检查
K是否属于F,取F[K]。 never是兜底(因为K一定属于F或S)。
- 结果:
- 合并后的对象包含
F和S的所有键。 - 冲突时
S覆盖F。
✅ 示例 5:判断是否为联合类型
TypeScript
Copy
type IsUnion<T, U = T> = T extends any
? [U] extends [T] ? false : true
: never;🔍 拆解过程
T extends any:触发 分布式条件类型(Distributive Conditional Types)。- 如果
T是联合类型(如A | B),会拆成A和B分别判断。
[U] extends [T]:U是原始联合类型(如A | B)。T是分布式后的单个成员(如A或B)。[A | B]不能扩展[A],所以返回true。
- 非联合类型:
- 如果
T不是联合类型(如string),[string] extends [string]为true,返回false。
🎯 核心技巧
- 分布式条件类型:
T extends any会拆分联合类型。 - 方括号
[]:阻止分布式行为,确保比较的是整体联合类型 vs 单个成员。
📌 一句话总结
Copy
| 示例 | 核心技巧 |
|---|---|
| 示例 3 | 递归 + 条件类型判断对象类型 |
| 示例 4 | 联合键遍历 + 条件分发优先级 |
| 示例 5 | 分布式条件类型 + 方括号阻止分发 |
需要我画流程图或再细化某一步吗?
Search
TypeScript 方括号 条件类型 分布式行为 官方文档 30 results
TypeScript 官方文档中明确说明了 “用方括号将
extends 关键字两侧括起来可以阻止分布式条件类型(distributive conditional types)” 的行为。原文如下(摘自 TypeScript 官方文档 ):
Distributed Conditional Types
When conditional types act on a generic type, they become distributive when given a union type.
[...]
Typically, distributivity is the desired behavior. To avoid that behavior, you can surround each side of theextendskeyword with square brackets.
示例代码:
TypeScript
Copy
// 默认行为:分布式
type ToArray<Type> = Type extends any ? Type[] : never;
type StrArrOrNumArr = ToArray<string | number>;
// => string[] | number[]
// 阻止分布式行为
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;
type StrOrNumArr = ToArrayNonDist<string | number>;
// => (string | number)[]