TypeScript进阶教程:从熟练到精通
🚀 前言
TypeScript已经成为现代前端开发不可或缺的工具,但很多开发者仅仅停留在基础类型注解的使用层面。本文将带你深入TypeScript的高级特性,掌握在实际项目中提升代码质量和开发效率的关键技巧。
💡 一、高级类型系统
1.1 条件类型(Conditional Types)
条件类型是TypeScript中强大的类型编程工具,它允许我们根据条件表达式创建动态类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| type IsString<T> = T extends string ? true : false;
type Test1 = IsString<'hello'>; type Test2 = IsString<123>;
type FilterString<T> = T extends string ? T : never;
type Mixed = string | number | boolean; type StringsOnly = FilterString<Mixed>;
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function getUser() { return { name: 'John', age: 30 }; }
type User = MyReturnType<typeof getUser>;
|
1.2 映射类型(Mapped Types)
映射类型允许我们基于现有类型创建新类型,这在处理对象类型时特别有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| type Readonly<T> = { readonly [P in keyof T]: T[P]; };
type Partial<T> = { [P in keyof T]?: T[P]; };
interface User { id: number; name: string; email: string; }
type ReadonlyUser = Readonly<User>;
type AddPrefix<T, P extends string> = { [K in keyof T as `${P}${Capitalize<string & K>}`]: T[K]; };
type PrefixedUser = AddPrefix<User, 'get'>;
|
1.3 模板字面量类型
TypeScript 4.1引入了模板字面量类型,使得字符串类型的操作更加灵活。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; type ApiEndpoint = `api/${string}`;
type FullEndpoint = `${HttpMethod} /${ApiEndpoint}`;
type Routes = 'users' | 'posts' | 'comments'; type HttpMethods = 'get' | 'post' | 'put' | 'delete';
type ApiRoutes = { [K in Routes as `${HttpMethods}${Capitalize<K>}`]: () => Promise<any>; };
|
二、装饰器深度应用
装饰器是TypeScript的实验性特性,但在很多框架中广泛使用。
2.1 类装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| function Controller(path: string) { return function <T extends { new (...args: any[]): {} }>(constructor: T) { return class extends constructor { routePath = path; readonly isController = true; }; }; }
function LogMethod(target: any, propertyName: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`调用方法: ${propertyName}, 参数:`, args); const result = originalMethod.apply(this, args); console.log(`方法 ${propertyName} 返回:`, result); return result; }; }
@Controller('/api/users') class UserController { private users: any[] = [];
@LogMethod addUser(user: any) { this.users.push(user); return user; }
@LogMethod getUsers() { return this.users; } }
|
2.2 参数装饰器与元数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import 'reflect-metadata';
function Validate(min?: number, max?: number) { return function (target: any, propertyKey: string, parameterIndex: number) { const existingValidations = Reflect.getOwnMetadata('validations', target, propertyKey) || []; existingValidations.push({ parameterIndex, min, max }); Reflect.defineMetadata('validations', existingValidations, target, propertyKey); }; }
function validateParameters(target: any, propertyName: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; const validations = Reflect.getOwnMetadata('validations', target, propertyName) || [];
descriptor.value = function (...args: any[]) { for (const validation of validations) { const value = args[validation.parameterIndex]; if (validation.min !== undefined && value < validation.min) { throw new Error(`参数 ${validation.parameterIndex} 必须大于等于 ${validation.min}`); } if (validation.max !== undefined && value > validation.max) { throw new Error(`参数 ${validation.parameterIndex} 必须小于等于 ${validation.max}`); } } return originalMethod.apply(this, args); }; }
class Calculator { @validateParameters multiply(@Validate(1) a: number, @Validate(1, 10) b: number) { return a * b; } }
|
💡 三、高级泛型技巧
3.1 泛型约束与条件分发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| type ToArray<T> = T extends any ? T[] : never;
type StringOrNumberArray = ToArray<string | number>;
type Exclude<T, U> = T extends U ? never : T; type Extract<T, U> = T extends U ? T : never;
interface ApiResponse<T = any> { data: T; status: number; message: string; }
class ApiClient { async request<T>(url: string): Promise<ApiResponse<T>>; async request<T>(url: string, data: any): Promise<ApiResponse<T>>; async request<T>(url: string, data?: any): Promise<ApiResponse<T>> { const config: RequestInit = data ? { method: 'POST', body: JSON.stringify(data), headers: { 'Content-Type': 'application/json' } } : { method: 'GET' };
const response = await fetch(url, config); const result = await response.json(); return { data: result as T, status: response.status, message: response.statusText }; } }
|
3.2 递归类型与高级模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| type DeepReadonly<T> = { readonly [P in keyof T]: T[P] extends object ? T[P] extends Function ? T[P] : DeepReadonly<T[P]> : T[P]; };
type DeepPartial<T> = { [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]; };
interface NestedObject { level1: { level2: { level3: { value: string; }; }; items: number[]; }; }
type ReadonlyNested = DeepReadonly<NestedObject>; type PartialNested = DeepPartial<NestedObject>;
type Paths<T> = T extends object ? { [K in keyof T]: K extends string ? T[K] extends object ? K | `${K}.${Paths<T[K]>}` : K : never; }[keyof T] : never;
type UserPaths = Paths<NestedObject>;
|
✨ 四、命名空间与模块高级用法
4.1 命名空间合并与声明合并
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| interface User { id: number; name: string; }
interface User { email: string; age?: number; }
namespace API { export interface Response<T> { data: T; success: boolean; } }
namespace API { export interface Error { code: number; message: string; } export function handleError(error: Error): void { console.error(`API Error ${error.code}: ${error.message}`); } }
const response: API.Response<User> = { data: { id: 1, name: 'John', email: '[email protected]' }, success: true };
|
4.2 高级模块模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| interface ServiceConfig { endpoint: string; timeout: number; }
abstract class BaseService { abstract initialize(config: ServiceConfig): void; }
class UserService extends BaseService { private static instance: UserService; private config!: ServiceConfig;
private constructor() { super(); }
static getInstance(): UserService { if (!UserService.instance) { UserService.instance = new UserService(); } return UserService.instance; }
initialize(config: ServiceConfig): void { this.config = config; }
async getUsers(): Promise<any[]> { const response = await fetch(this.config.endpoint, { signal: AbortSignal.timeout(this.config.timeout) }); return response.json(); } }
export const createService = <T extends BaseService>( ServiceClass: new () => T, config: ServiceConfig ): T => { const service = new ServiceClass(); service.initialize(config); return service; };
export { UserService }; export type { ServiceConfig };
|
五、性能优化与最佳实践
5.1 类型性能优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
enum Status { Pending = 'pending', Approved = 'approved', Rejected = 'rejected' }
const Status = { Pending: 'pending', Approved: 'approved', Rejected: 'rejected' } as const;
type Status = typeof Status[keyof typeof Status];
const ROUTES = { home: '/', about: '/about', contact: '/contact' } as const;
type Route = keyof typeof ROUTES;
type HeavyComputation<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;
declare const brand: unique symbol;
type Brand<T, B> = T & { [brand]: B }; type UserId = Brand<number, 'UserId'>; type ProductId = Brand<number, 'ProductId'>;
function createUserId(id: number): UserId { return id as UserId; }
function createProductId(id: number): ProductId { return id as ProductId; }
const userId: UserId = createUserId(1); const productId: ProductId = createProductId(1);
|
5.2 工程化配置技巧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| { "compilerOptions": { "strict": true, "exactOptionalPropertyTypes": true, "noUncheckedIndexedAccess": true, "noImplicitOverride": true, "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "allowSyntheticDefaultImports": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", "paths": { "@/*": ["src/*"], "@/components/*": ["src/components/*"], "@/utils/*": ["src/utils/*"] }, "declaration": true, "declarationMap": true, "sourceMap": true, "removeComments": false, "incremental": true, "tsBuildInfoFile": "./dist/.tsbuildinfo" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.test.ts"] }
|
🌟 六、实战案例:构建类型安全的API客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
interface ApiDefinition { path: string; method: HttpMethod; request?: any; response: any; }
interface ApiConfig { [key: string]: ApiDefinition; }
const apiConfig = { getUser: { path: '/users/:id', method: 'GET', response: { id: 0, name: '', email: '' } }, createUser: { path: '/users', method: 'POST', request: { name: '', email: '' }, response: { id: 0, name: '', email: '' } }, updateUser: { path: '/users/:id', method: 'PUT', request: { name: '', email: '' }, response: { success: true } } } as const;
class TypedApiClient { private baseURL: string;
constructor(baseURL: string) { this.baseURL = baseURL; }
async request< K extends keyof typeof apiConfig, T extends typeof apiConfig[K] >( key: K, ...args: T['request'] extends undefined ? [params?: Record<string, string>] : [data: T['request'], params?: Record<string, string>] ): Promise<T['response']> { const config = apiConfig[key]; let [data, params] = args as [any, Record<string, string>?]; if (params === undefined && data && !config.request) { params = data; data = undefined; }
let url = config.path; if (params) { url = url.replace(/:(\w+)/g, (_, key) => params![key] || ''); }
const response = await fetch(`${this.baseURL}${url}`, { method: config.method, headers: data ? { 'Content-Type': 'application/json' } : {}, body: data ? JSON.stringify(data) : undefined });
if (!response.ok) { throw new Error(`API Error: ${response.status}`); }
return response.json(); } }
const api = new TypedApiClient('https://api.example.com');
const user = await api.request('getUser', { id: '123' }); const newUser = await api.request('createUser', { name: 'John', email: '[email protected]' }); const result = await api.request('updateUser', { name: 'John Updated' }, { id: '123' });
|
👋 结语
通过本教程,我们深入探讨了TypeScript的高级特性,包括条件类型、映射类型、装饰器、高级泛型等。这些特性不仅能提升代码的类型安全性,还能显著提高开发效率和代码质量。掌握这些进阶技巧后,你将能够构建更加健壮、可维护的TypeScript应用程序。
记住,TypeScript的强大之处在于它的类型系统,合理利用这些高级特性,可以让你的代码在编译时就能发现潜在的错误,减少运行时的问题。继续实践和探索,你会发现TypeScript带来的更多价值。
[up主专用,视频内嵌代码贴在这]


零点119官方团队
一站式科技资源平台 | 学生/开发者/极客必备
本文由零点119官方团队原创,转载请注明出处。文章ID: 54f44a32