1. 工具类型
Partial
所有的字段都会被成可选的
typescript
interface AppConfig {
title: string;
version: number;
theme: 'light' | 'dark';
}
type PartialConfig = Partial<AppConfig>;
// Equivalent to: { title?: string; version?: number; theme?: 'light' | 'dark'; }
Pick
从一个类型中选中指定属性
typescript
interface AppConfig {
title: string;
version: number;
theme: 'light' | 'dark';
}
type TitleConfig = Pick<AppConfig, 'title' | 'version'>;
// Equivalent to: { title: string; version: number; }
Omit
从一个类型中排除指定属性
typescript
interface AppConfig {
title: string;
version: number;
theme: 'light' | 'dark';
}
type WithoutTheme = Omit<AppConfig, 'theme'>;
// Equivalent to: { title: string; version: number; }
Readonly
将所有属性变为只读
typescript
interface AppConfig {
title: string;
version: number;
theme: 'light' | 'dark';
}
type ReadonlyConfig = Readonly<AppConfig>;
// Equivalent to: { readonly title: string; readonly version: number; readonly theme: 'light' | 'dark'; }
Required
将所有属性变为必选
typescript
type RequiredConfig = Required<{
description?: string | null;
}>;
// Equivalent to: { description: string | null; }
这里要注意:
description?: string | null
和 description: string | null | undefined
是不一样的。
前一个代表 description
是可选的,后一个代表 description
的值可能是 undefined
。
Required
只会移除 ?
, 而不会去处理 undefined
。
ts
type RequiredConfig = Required<{
description: string | null | undefined;
}>;
// Equivalent to: { description: string | null | undefined; }
Record
创建一个对象类型,键为指定的类型,值为指定的类型
ts
type RecordConfig = Record<'vueApp' | 'ngApp', AppConfig>;
// Equivalent to: { vueApp: AppConfig; ngApp: AppConfig; }
Exclude
从联合类型中排除指定的类型
ts
type ExcludeConfig = Exclude<'a' | 'b' | 'c', 'b' | 'd'>;
// Equivalent to: 'a' | 'c'
Extract
从联合类型中提取交集的类型
ts
type ExtractConfig = Extract<'a' | 'b' | 'c', 'b' | 'd'>;
// Equivalent to: 'b'
NonNullable:
从联合类型中排除 null 和 undefined
ts
type NonNullableUnitType = NonNullable<string | null | undefined>;
// Equivalent to: string
但是它无法对类型进行非空处理
ts
type NonNullableType = NonNullable<{
description: string | null | undefined;
}>;
// 你预期的结果: { description: string; }
// 实际结果: { description: string | null | undefined; }
可以基于 NonNullable Map一个新的工具类型,实现上述需求
ts
type NonNullablePlus<T> = {
[K in keyof T]: NonNullable<T[K]>;
};
type NonNullableType = NonNullablePlus<{
description: string | null | undefined;
}>;
// Equivalent to: { description: string; }
Parameters
提取函数参数类型, 返回数组
ts
declare function f1(arg: { a: number; b: string }, arg2: string): void;
type F1Parameters = Parameters<typeof f1>;
// Equivalent to: [arg: { a: number; b: string; }, arg2: string]
type T1 = Parameters<() => void>;
// Equivalent to: []
ConstructorParameters
提取类的构造函数参数, 返回数组
ts
class C {
constructor(a: number, b: string) {}
}
type TCConstructorParameters = ConstructorParameters<typeof C>;
// Equivalent to: [a: number, b: string]
ReturnType
提取函数返回值类型
ts
declare function f1(): { a: number; b: string };;
type F1ReturnType = ReturnType<typeof f1>;
// Equivalent to: { a: number; b: string; }
InstanceType
提取类的类型
ts
class C {
x = 0;
y = 0;
constructor(a: number, b: string) {}
}
type CType = InstanceType<typeof C>;
// Equivalent to: C
NoInfer
- 强制用户显式的指定泛型类型
ts
function useValue<T>(value: NoInfer<T>): T {
return value;
}
const explicitValue = useValue<string>("hello"); // OK
const inferredValue = useValue("hello"); // Error: 必须显式的指定类型
- 防止泛型类型推断
ts
function createStreetLight<C extends string>(
colors: C[],
defaultColor?: NoInfer<C>,
) {
// ...
}
createStreetLight(["red", "yellow"], ); // OK
createStreetLight(["red", "yellow", "green"], "blue"); // Error
这里,NoInfer<C>
确保 defaultColor
的类型必须显式匹配 C
,而不会被推断为其他类型。
- 防止默认类型被覆盖
ts
function createStore<T = { default: true }>(state: NoInfer<T>): T {
return state;
}
const store = createStore(); // 类型为 { default: true }
const customStore = createStore({ custom: true }); // Error: 类型推断被阻止
2. 模板字面量类型
它可以基于字符串模板创建类型。
Capitalize<StringType>
可以将字符串字面量类型的第一个字符转换为大写。
typescript
type Event = 'click' | 'hover';
type EventHandler = `on${Capitalize<Event>}`;
const handler: EventHandler = 'onClick'; // 或 'onHover'
除了 Capitalize
外,还有其它几个
Uncapitalize<StringType>
:将字符串字面量类型的第一个字符转换为小写。Uppercase<StringType>
:将字符串字面量类型的所有字符转换为大写。Lowercase<StringType>
:将字符串字面量类型的所有字符转换为小写。
你可以结合 keyof
自己创建一些更有用的工具类型
ts
type UppercaseKeys<T> = {
[K in keyof T as Uppercase<K & string>]: T[K];
};
type Example = UppercaseKeys<{ name: string; age: number }>;
// Equivalent to: { NAME: string; AGE: number }
3. keyof
3.1 获取对象类型的键
ts
type Person = {
name: string;
age: number;
isStudent: boolean;
};
type PersonKeys = keyof Person;
// Equivalent to: 'name' | 'age' | 'isStudent'
3.2 使用 keyof
限制键的类型
ts
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const person = { name: 'Alice', age: 25 };
const name = getValue(person, 'name'); // OK, 返回类型为 string
const age = getValue(person, 'age'); // OK, 返回类型为 number
// const invalid = getValue(person, 'height'); // Error: 类型 '"height"' 不可分配给参数
3.3 map 类型
可以用 Partial
作为例子
ts
/**
* Make all properties in T required
*/
type Required<T> = {
[P in keyof T]-?: T[P];
};
这里 -?
的作用是从属性中移除可选标记(?
)。它的作用是将类型中的所有可选属性变为必选属性。
4. infer
它用于条件中的类型推导。
Typescript 官网拿 ReturnType
这一经典例子来演示它的作用
ts
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
如果 T
继承了 (...args: any[]) => any
类型,则返回类型 R
,否则返回 any
。其中的 R
是从传入参数类型中推导出来的,infer相当于一个类型占位。
可以结合上面 ReturnType
中的例子来看
ts
declare function f1(): { a: number; b: string };;
type F1ReturnType = ReturnType<typeof f1>;
// Equivalent to: { a: number; b: string; }
5. as const
as const
将一个对象或数组的所有属性变为 只读 ,并将其值的类型从宽泛的类型(如 string
、number
)缩小为更具体的类型(如 'value'
或 1
)。
ts
const data = { age: 1 };
type DataType = typeof data;
// Equivalent to: { age: number; }
const dataConst = { age: 1 } as const;
type DataConstType = typeof dataConst;
// Equivalent to: { readonly age: 1; }
它可以与 typeof
一起使用,从常量中提取更具体的类型。
ts
const COLORS = {
RED: 'red',
GREEN: 'green',
BLUE: 'bl?
type Color = typeof COLORS[keyof typeof COLORS];
// Equivalent to: 'red' | 'green' | 'blue'
const directions = ['up', 'down', 'left', 'right'] as const;
type Direction = typeof directions[number];
// Equivalent to: 'up' | 'down' | 'left' | 'right'
6. 泛型约束
通过 extends
关键字,可以对泛型进行约束,限制泛型的类型范围。
ts
function getLength<T extends { length: number }>(arg: T): number {
return arg.length;
}
getLength('Hello'); // OK, string 有 length 属性
getLength([1, 2, 3]); // OK, 数组有 length 属性
// getLength(42); // Error: number 没有 length 属性
7. 根据枚举值,动态生成类型
ts
enum ShapeType {
Square = 1,
Circle = 2
}
interface Square {
size: number;
}
interface Circle {
radius: number;
}
type MutableRecord<T> = {
[SubType in keyof T]: {
type: SubType;
} & { [K in keyof T[SubType]]: T[SubType][K] };
}[keyof T];
type Shape = MutableRecord<{
[ShapeType.Square]: Square;
[ShapeType.Circle]: Circle;
}>;
const circle: Shape = {
type: ShapeType.Circle,
radius: 1, // 这里只会出现 radius
};
const square: Shape = {
type: ShapeType.Square,
size: 1, // 这里只会出现 size
};
持续更新中...