返回首页'%2F%3E%3Ctext%20x%3D'50%25'%20y%3D'50%25'%20dy%3D'.35em'%20text-anchor%3D'middle'%20font-family%3D'sans-serif'%20font-size%3D'34'%20fill%3D'%23ffffff'%3E%E5%B0%8F%3C%2Ftext%3E%3C%2Fsvg%3E)
TypeScript 类型体操:从入门到实用
为什么需要高级类型
TypeScript 不只是给 JavaScript 加了类型标注。它的类型系统本身是图灵完备的,可以在编译期进行复杂的类型计算。合理使用高级类型,可以让错误在编译期暴露,减少运行时 Bug。
泛型:类型的参数
function identity<T>(value: T): T {
return value;
}
// 泛型约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 25 };
const name = getProperty(user, "name"); // 类型推断为 string
条件类型
条件类型让你可以基于类型关系做判断:
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<42>; // false
infer 关键字
infer 可以在条件类型中提取类型变量:
// 提取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
// 提取 Promise 的值类型
type Awaited<T> = T extends Promise<infer U> ? U : T;
type Result = Awaited<Promise<string>>; // string
映射类型
映射类型可以基于一个类型生成新类型:
// 将所有属性变为可选
type Optional<T> = {
[K in keyof T]?: T[K];
};
// 将所有属性变为只读
type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
// 将所有属性变为可空
type Nullable<T> = {
[K in keyof T]: T[K] | null;
};
实用类型工具
Pick 与 Omit
interface User {
id: number;
name: string;
email: string;
password: string;
}
// 只取部分字段
type PublicUser = Pick<User, "id" | "name" | "email">;
// 排除部分字段
type SafeUser = Omit<User, "password">;
Record 与 Partial
// 字典类型
type RolePermissions = Record<"admin" | "editor" | "viewer", string[]>;
// 表单状态
type FormState = Partial<User>;
模板字面量类型
type EventName = "click" | "hover" | "focus";
type EventHandler = `on${Capitalize<EventName>}`;
// "onClick" | "onHover" | "onFocus"
// API 路由类型
type ApiRoute = `/api/${string}`;
类型守卫
类型守卫帮助 TypeScript 收窄类型范围:
function process(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase(); // 这里 value 是 string
}
return value.toFixed(2); // 这里 value 是 number
}
// 自定义类型守卫
function isApiError(error: unknown): error is { code: number; message: string } {
return (
typeof error === "object" &&
error !== null &&
"code" in error &&
"message" in error
);
}
实战:类型安全的 EventEmitter
class TypedEmitter<Events extends Record<string, any>> {
private handlers: { [K in keyof Events]?: Array<(data: Events[K]) => void> } = {};
on<K extends keyof Events>(event: K, handler: (data: Events[K]) => void) {
(this.handlers[event] ??= []).push(handler);
}
emit<K extends keyof Events>(event: K, data: Events[K]) {
this.handlers[event]?.forEach((h) => h(data));
}
}
// 使用
interface MyEvents {
login: { userId: string };
logout: void;
}
const emitter = new TypedEmitter<MyEvents>();
emitter.on("login", (data) => {
console.log(data.userId); // 类型安全!
});
总结
TypeScript 的类型系统是一门艺术。从泛型到条件类型,从映射类型到模板字面量类型——每一层都让你离"编译期消灭 Bug"更近一步。
原则:类型应该帮你减少错误,而不是增加心智负担。适度使用,过犹不及。
小楼春雨
@站长