TypeScript的高级类型系统是大型前端项目的类型安全基石。泛型让组件和函数具备类型复用能力,类型守卫在运行时收窄类型范围,条件类型和映射类型则实现类型层面的逻辑运算。实际开发中合理使用这些特性,可以在编译阶段消除大量运行时错误。
泛型函数与泛型约束
泛型函数允许类型参数化,在不丢失类型信息的前提下实现逻辑复用:
// 基础泛型:类型参数T在调用时确定
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "张三", age: 30, email: "zhang@example.com" };
const userName = getProperty(user, "name"); // 类型推断为 string
const userAge = getProperty(user, "age"); // 类型推断为 number
// 泛型约束:限制类型参数必须满足特定结构
interface HasId {
id: number;
}
function findById<T extends HasId>(items: T[], id: number): T | undefined {
return items.find(item => item.id === id);
}
// 泛型默认类型
function createArray<T = string>(length: number, value: T): T[] {
return Array.from({ length }, () => value);
}
const strArray = createArray(3, "hello"); // string[]
const numArray = createArray<number>(3, 42); // number[]
API请求函数中的泛型应用:
interface ApiResponse<T> {
code: number;
message: string;
data: T;
}
async function request<T>(url: string, options?: RequestInit): Promise<T> {
const res = await fetch(url, options);
const json: ApiResponse<T> = await res.json();
if (json.code !== 0) {
throw new Error(json.message);
}
return json.data;
}
// 调用时自动推断返回类型
interface User { id: number; name: string; }
const user = await request<User>("/api/user/1"); // 类型为 User
类型守卫与类型收窄
类型守卫在运行时检查类型,帮助TypeScript编译器收窄联合类型:
// typeof 类型守卫
function processValue(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase(); // 此处 value 类型收窄为 string
}
return value.toFixed(2); // 此处 value 类型收窄为 number
}
// instanceof 类型守卫
class ValidationError extends Error {
constructor(public field: string, message: string) {
super(message);
}
}
function handleError(error: Error | ValidationError) {
if (error instanceof ValidationError) {
return `${error.field}: ${error.message}`; // 可访问 field 属性
}
return error.message;
}
// in 操作符类型守卫
interface ApiSuccess { data: unknown; }
interface ApiError { error: string; }
function handleResponse(response: ApiSuccess | ApiError) {
if ("data" in response) {
return response.data; // 类型收窄为 ApiSuccess
}
throw new Error(response.error); // 类型收窄为 ApiError
}
自定义类型守卫函数处理复杂联合类型:
interface TextNode {
type: "text";
content: string;
}
interface ImageNode {
type: "image";
url: string;
width: number;
height: number;
}
interface VideoNode {
type: "video";
url: string;
duration: number;
}
type ContentNode = TextNode | ImageNode | VideoNode;
// 自定义类型谓词
function isImageNode(node: ContentNode): node is ImageNode {
return node.type === "image";
}
function renderNode(node: ContentNode): string {
switch (node.type) {
case "text":
return `<p>${node.content}</p>`;
case "image":
return `<img src="${node.url}" width="${node.width}" height="${node.height}"/>`;
case "video":
return `<video src="${node.url}" duration="${node.duration}"></video>`;
}
}
// 类型谓词在数组过滤中的应用
const nodes: ContentNode[] = [...];
const images = nodes.filter(isImageNode); // 类型为 ImageNode[]
条件类型与映射类型
条件类型实现类型层面的条件判断:
// 提取Promise的泛型参数
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type R1 = UnwrapPromise<Promise<string>>; // string
type R2 = UnwrapPromise<number>; // number
// 提取函数返回类型
type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never;
// 排除特定属性
type OmitMethod<T> = {
[K in keyof T]: T[K] extends Function ? never : K
}[keyof T];
type DataProps = OmitMethod<{ name: string; age: number; greet(): void }>;
// "name" | "age"
映射类型实现类型转换:
// 所有属性变为可选
type Partial<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 };
// 将对象键名转为联合类型
type ObjectValues<T> = T[keyof T];
const config = {
apiBase: "/api",
timeout: 5000,
retryCount: 3
} as const;
type ConfigValue = ObjectValues<typeof config>;
// "/api" | 5000 | 3
实际业务场景中的类型设计
表单验证场景,利用泛型和映射类型构建类型安全的验证器:
type ValidationRule<T> = {
[K in keyof T]?: {
required?: boolean;
min?: number;
max?: number;
pattern?: RegExp;
validator?: (value: T[K]) => boolean | string;
};
};
interface LoginForm {
username: string;
password: string;
}
const rules: ValidationRule<LoginForm> = {
username: {
required: true,
min: 3,
max: 20,
pattern: /^[a-zA-Z0-9_]+$/
},
password: {
required: true,
min: 8,
validator: (value) => value.length >= 8 || "密码至少8位"
}
};
function validate<T>(data: T, rules: ValidationRule<T>): Record<string, string> {
const errors: Record<string, string> = {};
for (const key in rules) {
const rule = rules[key];
const value = data[key];
if (rule?.required && !value) {
errors[key] = `${key}不能为空`;
}
if (rule?.min && typeof value === "string" && value.length < rule.min) {
errors[key] = `${key}最少${rule.min}个字符`;
}
}
return errors;
}
泛型和高级类型的使用需要控制复杂度。简单业务逻辑用基础类型即可,过度使用泛型嵌套会降低代码可读性。核心原则:泛型用于可复用的工具函数和组件,类型守卫用于联合类型处理,条件类型用于类型工具库,业务代码以清晰可维护优先。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/typescript-fan-xing-yu-lei-xing-shou-wei-shi-zhan-gao-ji/