解读TypeScript 类型工具
TypeScript 类型工具是用于操作和转换类型的编程手段,主要通过类型系统实现更安全的类型操作。接下来我将介绍代码 中常设计的主要类型工具以及作用
一、基础对象类型操作
1. Partial<T>
- 作用:将对象类型
T
的所有属性变为可选。 - 示例:
interface User { name: string; age: number; } type PartialUser = Partial<User>; // { name?: string; age?: number }
- 实现:通过映射类型
{ [P in keyof T]?: T[P] }
实现 。
2. Required<T>
- 作用:将对象类型
T
的所有属性变为必填。 - 示例:
interface Props { a?: number; } type RequiredProps = Required<Props>; // { a: number }
- 实现:使用
-?
操作符移除可选性:{ [P in keyof T]-?: T[P] }
,同理使用+?表示增加可选属性,[P in keyof T]+?: T[P];
3. Readonly<T>
- 作用:将对象类型
T
的所有属性变为只读。 - 示例:
const todo: Readonly<Todo> = { title: "Read TS" }; todo.title = "Error"; // 编译错误
- 实现:通过
readonly
修饰符实现映射:{ readonly [P in keyof T]: T[P] }
,同样的-readonly
表示去除属性的只读标志。
4.ReadonlyArray<T>
作用:与上面类型工具相同,这里
用来生成一个只读数组类型- 示例:
const values: ReadonlyArray<string> = ['a', 'b', 'c']; values[0] = 'x'; // 报错 values.push('x'); // 报错 values.pop(); // 报错 values.splice(1, 1); // 报错
5. Record<K, T>
- 作用:参数
K
用作键名,参数T
用作键值类型。 - 示例1:
// 普通对象类型写法 type T = { a: number };// Record 写法 type T = Record<'a', number>;
- 示例2:当键是联合类型时更有用:
type Keys = 'name' | 'age'; type Person = Record<Keys, string>; // 等价于 { name: string; age: string }
- 实现:基于联合类型的键映射:
{ [P in K]: T }
。
6. Pick<T, K>
- 作用:从
T
中选取指定键K
组成新类型。 - 示例:
interface A {x: number;y: number; } type T1 = Pick<A, 'x'>; // { x: number } type T2 = Pick<A, 'y'>; // { y: number } type T3 = Pick<A, 'x'|'y'>; // { x: number; y: number }
- 实现:通过
K extends keyof T
约束和键过滤实现 。
7. Omit<T, K>
- 作用:用来从对象类型
T
中,删除指定的属性K
,组成一个新的对象类型返回。 - 示例:
interface A {x: number;y: number; } type T1 = Omit<A, 'x'>; // { y: number } type T2 = Omit<A, 'y'>; // { x: number } type T3 = Omit<A, 'x' | 'y'>; // { }
- 实现:结合
Exclude
和Pick
:Pick<T, Exclude<keyof T, K>>
。
二、联合类型操作
1. Exclude<T, U>
- 作用:从联合类型
T
中排除可赋值给U
的类型。 - 示例:
type T = Exclude<"a" | "b" | "c", "a">; // "b" | "c" type T1 = Exclude<string|(() => void), Function>; // string
- 实现:通过条件类型
T extends U ? never : T
实现 。
2. Extract<T, U>
- 作用:用来从联合类型T之中,提取指定类型
U
,组成一个新类型返回。它与Exclude<T, U>
正好相反。 - 示例:
type T = Extract<string | (() => void), Function>; // () => void
- 实现:使用
T extends U ? T : never
。
3. NonNullable<T>
- 作用:排除
T
中的null
和undefined
。 - 示例:
type T = NonNullable<string | null>; // string
- 实现:通过交叉类型
T & {}
或条件类型过滤 。
三、函数与类操作
1. Parameters<T>
- 作用:提取函数类型
T
的参数类型为元组。 - 示例:
type T1 = Parameters<() => string>; // [] type T2 = Parameters<(s:string) => void>; // [s:string] type T3 = Parameters<<T>(arg: T) => T>; // [arg: unknown]export function getGift(name: SecretName,gift: string ): SecretSanta {// ... }type ParaT = Parameters<typeof getGift>[0]; // SecretName type ReturnT = ReturnType<typeof getGift>; // SecretSanta
- 实现:
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P)=> any ? P : never
2. ReturnType<T>
- 作用:提取函数类型
T
的返回值类型,注意与上一个类型工具做区分。 - 示例:
type R = ReturnType<() => number>; // numbertype R1 = ReturnType<(s:string) => void>; // void type R2 = ReturnType<() => () => any[]>; // () => any[] type R3 = ReturnType<typeof Math.random>; // number type R4 = ReturnType<typeof Array.isArray>; // boolean
- 实现:通过
infer R
推断返回类型 。
3. ConstructorParameters<T>
- 作用:提取构造函数参数类型为元组。
- 示例:
class C { constructor(x: string) {} } type CP = ConstructorParameters<typeof C>; // [string]
- 实现:结合
new
关键字和参数推断 。
4. InstanceType<T>
- 作用:提提取构造函数的返回值的类型(即实例类型),参数
T
是一个构造函数,等同于构造函数的ReturnType<Type>
。 - 示例:
type CInstance = InstanceType<typeof C>; // C
- 实现:通过
infer R
捕获实例类型 。 - 注意:如果参数不是构造类型,就会报错
type T1 = InstanceType<string>; // 报错 type T2 = InstanceType<Function>; // 报错
四、字符串与模板操作
1. Uppercase<S>
/ Lowercase<S>
- 作用:转换字符串类型
S
为全大写或全小写。 - 示例:
type T = Uppercase<"hello">; // "HELLO" type B = Lowercase<HELLO>; // "hello"
- 应用:常用于动态生成枚举键或事件名 。
2. Capitalize<S>
/ Uncapitalize<S>
- 作用:转换首字母为大写或小写。
- 示例:
type T = Capitalize<"typescript">; // "Typescript" type B = Uncapitalize<HELLO>; // "hELLO"
3. 模板字面量类型
- 作用:通过模板字符串组合类型。
- 示例:
type EventType = `on${Capitalize<"click" | "hover">}`; // "onClick" | "onHover"
五、高级工具类型
1. Awaited<T>
- 作用:用来取出 Promise 的返回值类型,适合用在描述
then()
方法和 await 命令的参数类型。 - 示例:
type R = Awaited<Promise<Promise<number>>>; // number
- 实现:通过条件类型和递归解包实现 。
2. ThisType<T>
- 作用:用来跟其他类型组成交叉类型,用来提示 TypeScript 其他类型里面的
this
的类型。 - 示例:
const obj = {data: { x: 0 },methods: {move() { this.x++; } // this 类型为 { x: number }} } as ThisType<{ x: number }>;
六、使用时注意
- 组合工具类型:
type ReadOnlyPartial<T> = Readonly<Partial<T>>;
- 运行时验证:结合
zod
或io-ts
实现类型安全的数据校验 。 - 避免
any
:优先使用unknown
和类型断言(as
)保证安全性 。 - 避免过度依赖
as
和!
类型断言(as
)和非空断言(!)会绕过 TypeScript 的静态检查,可能导致运行时错误。