TypeScript
是现代 JavaScript
开发中不可或缺的工具,它提供了类型安全和丰富的特性。许多开发者掌握了基本用法,但还有一些鲜为人知的技巧可以让你的代码更高效、干净且易于维护。接下来,让我们深入探讨每位开发者应该了解的20个 TypeScript
技巧,附带示例和实用建议!
-
非空类型 (
NonNullable
)NonNullable
工具类型可以消除类型中的null
和undefined
,帮助你避免空值问题。type User = { name: string; age?: number | null }; const user: NonNullable<User["age"]> = 30; // 不允许 null 或 undefined
-
使用
Partial
增强灵活性Partial<T>
将类型中的所有属性设为可选,非常适合更新对象字段的子集。interface User { name: string; age: number; email: string; } const updateUser = (user: Partial<User>) => { return { ...user, updatedAt: new Date() }; }; updateUser({ name: 'John' }); // 不需提供完整对象
-
利用
Readonly
实现不可变数据Readonly<T>
将类型的所有属性设为只读,防止修改。const config: Readonly<{ apiUrl: string; retries: number }> = { apiUrl: 'https://api.example.com', retries: 5 }; // config.apiUrl = 'https://newapi.com'; // 错误:只读属性
-
映射类型实现动态属性类型
映射类型允许通过转换已有类型创建新类型,非常适合创建对象类型变体。
type Status = 'loading' | 'success' | 'error'; type ApiResponse<T> = { [K in Status]: T; }; const response: ApiResponse<string> = { loading: '加载中...', success: '数据加载成功', error: '出现错误' };
-
带可选元素的元组类型
TypeScript
支持在元组中使用可选元素,适合处理变参函数。type UserTuple = [string, number?, boolean?]; const user1: UserTuple = ['Alice']; // 仅名字 const user2: UserTuple = ['Bob', 30]; // 名字和年龄 const user3: UserTuple = ['Charlie', 25, true]; // 完整元组
-
使用联合类型进行全面检查
在
switch
语句中确保处理所有联合类型情况,以避免遗漏。type Status = 'open' | 'closed' | 'pending'; function handleStatus(status: Status) { switch (status) { case 'open': return '已打开'; case 'closed': return '已关闭'; case 'pending': return '待处理'; default: const exhaustiveCheck: never = status; // 未处理的状态类型会报错 return exhaustiveCheck; } }
-
使用
Omit
排除键使用
Omit
创建一个排除特定键的对象类型,方便管理。interface Todo { title: string; description: string; completed: boolean; } type TodoPreview = Omit<Todo, 'description'>; const todo: TodoPreview = { title: '学习 TypeScript', completed: false };
-
使用
in
和instanceof
进行类型细化利用
in
和instanceof
在运行时细化类型,确保代码安全。function processInput(input: string | number | { title: string }) { if (typeof input === 'string') { return input.toUpperCase(); // 细化为字符串 } else if (typeof input === 'number') { return input * 2; // 细化为数字 } else if ('title' in input) { return input.title; // 细化为对象 } }
-
使用条件类型实现高级类型逻辑
条件类型提供了灵活的类型转换。
type IsString<T> = T extends string ? true : false; type CheckString = IsString<'Hello'>; // true type CheckNumber = IsString<42>; // false
-
使用
as const
冻结字面量类型as const
可以确保值被视为字面量类型,避免可变性。const COLORS = ['red', 'green', 'blue'] as const; type Color = typeof COLORS[number]; // 'red' | 'green' | 'blue'
-
使用
Extract
和Exclude
精炼类型通过
Extract
和Exclude
从联合类型中选择或过滤类型。type T = 'a' | 'b' | 'c'; type OnlyAOrB = Extract<T, 'a' | 'b'>; // 'a' | 'b' type ExcludeC = Exclude<T, 'c'>; // 'a' | 'b'
-
自定义类型保护
创建类型保护函数以动态精确化类型。
function isString(input: any): input is string { return typeof input === 'string'; } const value: any = 'Hello'; if (isString(value)) { console.log(value.toUpperCase()); // 安全:value 是字符串 }
-
使用
Record
创建动态对象类型Record<K, V>
适合创建具有动态键的对象类型。type Role = 'admin' | 'user' | 'guest'; const permissions: Record<Role, string[]> = { admin: ['read', 'write', 'delete'], user: ['read', 'write'], guest: ['read'] };
-
动态类属性与索引签名
索引签名可以让你创建具有动态属性名的对象或类。
class DynamicObject { [key: string]: any; } const obj = new DynamicObject(); obj.name = 'Alice'; obj.age = 30;
-
使用
never
类型表示不可能的状态never
类型表示不应出现的值,通常用于全面检查。function assertNever(value: never): never { throw new Error(`意外的值: ${value}`); }
-
可选链用于安全属性访问
可选链(
?.
)可以安全访问深层嵌套的属性。const user = { profile: { name: 'John' } }; const userName = user?.profile?.name; // 'John' const age = user?.profile?.age ?? '未提供'; // 默认值
-
空值合并运算符(
??
)使用空值合并运算符提供默认值,仅在值为
null
或undefined
时生效。const input: string | null = null; const defaultValue = input ?? '默认值'; // '默认值'
-
使用
ReturnType
推断返回类型ReturnType<T>
可以提取函数的返回类型,处理复杂类型时十分有用。function getUser() { return { name: 'John', age: 30 }; } type UserReturn = ReturnType<typeof getUser>; // { name: string; age: number; }
-
函数中的类型参数
泛型类型参数使函数在不同类型间更灵活。
function identity<T>(value: T): T { return value; } identity<string>('Hello'); // 'Hello' identity<number>(42); // 42
-
交叉类型用于合并结构
交叉类型允许将多个类型合并为一个。
type Admin = { privileges: string[] }; type User = { name: string }; type AdminUser = Admin & User; const adminUser: AdminUser = { privileges: ['admin', 'editor'], name: 'Alice' };
这些技巧将帮助你将 TypeScript
技能提升到新层次!