第三部分:高级特性与最佳实践
1. 装饰器
1.1 类装饰器
typescript
// 基础类装饰器
function Logger(constructor: Function) {
console.log('Class created:', constructor.name);
}
// 装饰器工厂
function LoggerFactory(logString: string) {
return function(constructor: Function) {
console.log(logString);
console.log(constructor);
};
}
// 替换类定义的装饰器
function WithTemplate(template: string, hookId: string) {
return function<T extends { new(...args: any[]): { name: string } }>(
originalConstructor: T
) {
return class extends originalConstructor {
constructor(...args: any[]) {
super();
console.log('Rendering template');
const hookEl = document.getElementById(hookId);
if (hookEl) {
hookEl.innerHTML = template;
hookEl.querySelector('h1')!.textContent = this.name;
}
}
};
};
}
// 使用装饰器
@Logger
@LoggerFactory('LOGGING')
@WithTemplate('<h1>My Person Object</h1>', 'app')
class Person {
name = 'Max';
constructor() {
console.log('Creating person object...');
}
}1.2 方法装饰器
typescript
// 方法装饰器
function LogMethod(
target: any,
propertyName: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyName} with args:`, args);
const result = originalMethod.apply(this, args);
console.log(`Result:`, result);
return result;
};
return descriptor;
}
// 自动绑定 this
function Autobind(
_target: any,
_methodName: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
const adjustedDescriptor: PropertyDescriptor = {
configurable: true,
enumerable: false,
get() {
const boundFn = originalMethod.bind(this);
return boundFn;
}
};
return adjustedDescriptor;
}
class Calculator {
@LogMethod
add(a: number, b: number): number {
return a + b;
}
@Autobind
multiply(a: number, b: number): number {
return a * b;
}
}1.3 属性装饰器
typescript
// 属性装饰器
function LogProperty(
target: any,
propertyName: string
) {
let value: any;
const getter = function() {
console.log(`Getting ${propertyName}: ${value}`);
return value;
};
const setter = function(newVal: any) {
console.log(`Setting ${propertyName} to: ${newVal}`);
value = newVal;
};
Object.defineProperty(target, propertyName, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
// 参数装饰器
function LogParameter(
target: any,
methodName: string,
parameterIndex: number
) {
console.log(`Parameter decorator for ${methodName}`);
console.log(`Parameter index: ${parameterIndex}`);
}
class Product {
@LogProperty
title: string;
private _price: number;
constructor(title: string, price: number) {
this.title = title;
this._price = price;
}
getPriceWithTax(@LogParameter tax: number): number {
return this._price * (1 + tax);
}
}2. 命名空间与模块
2.1 命名空间
typescript
// 基础命名空间
namespace Geometry {
export interface Point {
x: number;
y: number;
}
export class Circle {
constructor(public center: Point, public radius: number) {}
area(): number {
return Math.PI * this.radius * this.radius;
}
}
export namespace Advanced {
export function distance(p1: Point, p2: Point): number {
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
return Math.sqrt(dx * dx + dy * dy);
}
}
}
// 使用命名空间
const point: Geometry.Point = { x: 0, y: 0 };
const circle = new Geometry.Circle(point, 5);
console.log(circle.area());
console.log(Geometry.Advanced.distance({ x: 0, y: 0 }, { x: 3, y: 4 }));
// 命名空间合并
namespace Geometry {
export class Rectangle {
constructor(
public topLeft: Point,
public width: number,
public height: number
) {}
area(): number {
return this.width * this.height;
}
}
}2.2 ES6 模块
typescript
// math.ts - 模块导出
export const PI = 3.14159;
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
// 默认导出
export default class Calculator {
static square(x: number): number {
return x * x;
}
}
// 命名空间风格导出
export * as Geometry from './geometry';
// utils.ts - 模块导入
import Calculator, { PI, add } from './math';
import * as MathUtils from './math';
import { multiply as mul } from './math';
// 动态导入
async function loadMathModule() {
const math = await import('./math');
console.log(math.PI);
}3. 高级类型技巧
3.1 条件类型
typescript
// 基础条件类型
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
T extends Function ? "function" :
"object";
// infer 关键字
type UnpackPromise<T> = T extends Promise<infer U> ? U : T;
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArray = ToArray<string | number>; // string[] | number[]
// 排除条件分布
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
type StrOrNumArray2 = ToArrayNonDist<string | number>; // (string | number)[]3.2 映射类型
typescript
// 基础映射类型
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
type Required<T> = {
[P in keyof T]-?: T[P];
};
// 键重映射
type Getters<T> = {
[P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};
type RemoveKindField<T> = {
[P in keyof T as Exclude<P, "kind">]: T[P];
};
// 条件映射
type ExtractMethods<T> = {
[K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];
type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>;3.3 模板字面量类型
typescript
// 基础模板类型
type Email = `${string}@${string}.${string}`;
type CSSUnit = `${number}px` | `${number}em` | `${number}rem` | `${number}%`;
// 类型推断
type EventName<T extends string> = `${T}Changed`;
type Concat<S1 extends string, S2 extends string> = `${S1}${S2}`;
// 高级模式
type PropEventSource<T> = {
on<Key extends string & keyof T>(
eventName: `${Key}Changed`,
callback: (newValue: T[Key]) => void
): void;
};
// 实用类型
type PathImpl<T, Key extends keyof T> =
Key extends string
? T[Key] extends Record<string, any>
? `${Key}.${PathImpl<T[Key], Exclude<keyof T[Key], keyof any[]>> & string}`
: never
: never;
type Path<T> = PathImpl<T, keyof T> | keyof T;4. 实用工具类型
4.1 TypeScript 内置工具类型
typescript
// Partial<T> - 所有属性变为可选
interface User {
name: string;
age: number;
email: string;
}
type PartialUser = Partial<User>;
// Required<T> - 所有属性变为必需
type RequiredUser = Required<PartialUser>;
// Readonly<T> - 所有属性变为只读
type ReadonlyUser = Readonly<User>;
// Record<K, T> - 构造对象类型
type PageInfo = Record<'home' | 'about' | 'contact', { title: string }>;
// Pick<T, K> - 选择部分属性
type UserNameAndEmail = Pick<User, 'name' | 'email'>;
// Omit<T, K> - 排除部分属性
type UserWithoutEmail = Omit<User, 'email'>;
// Exclude<T, U> - 从联合类型中排除
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
// Extract<T, U> - 提取联合类型中的子集
type T1 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
// NonNullable<T> - 排除 null 和 undefined
type T2 = NonNullable<string | number | null | undefined>; // string | number
// Parameters<T> - 获取函数参数类型
type T3 = Parameters<(x: number, y: string) => void>; // [number, string]
// ReturnType<T> - 获取函数返回类型
type T4 = ReturnType<() => string>; // string
// InstanceType<T> - 获取构造函数实例类型
class C {
x = 0;
y = 0;
}
type T5 = InstanceType<typeof C>; // C
// ThisParameterType<T> - 获取 this 参数类型
function toHex(this: Number) {
return this.toString(16);
}
type T6 = ThisParameterType<typeof toHex>; // Number
// OmitThisParameter<T> - 移除 this 参数
type T7 = OmitThisParameter<typeof toHex>; // () => string4.2 自定义实用类型
typescript
// 深度可选
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
// 深度只读
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
// 深度必需
type DeepRequired<T> = {
[P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P];
};
// 可空转不可空
type NonNullableField<T, K extends keyof T> = {
[P in keyof T]: P extends K ? NonNullable<T[P]> : T[P];
};
// 值类型
type ValueOf<T> = T[keyof T];
// 异步返回值
type AsyncReturnType<T extends (...args: any) => any> =
T extends (...args: any) => Promise<infer R> ? R : never;
// 构造函数类型
type Constructor<T = {}> = new (...args: any[]) => T;
// 提取数组元素类型
type ArrayElement<A> = A extends readonly (infer T)[] ? T : never;
// 获取 Promise 的解析类型
type Awaited<T> = T extends PromiseLike<infer U> ? U : T;
// 可选属性转必需
type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
// 排除 never 类型
type ExcludeNever<T> = Pick<T, { [K in keyof T]: T[K] extends never ? never : K }[keyof T]>;5. 错误处理与调试
5.1 类型安全的错误处理
typescript
// Result 模式
type Result<T, E = Error> =
| { success: true; value: T }
| { success: false; error: E };
function safeParseJSON<T = any>(json: string): Result<T> {
try {
const value = JSON.parse(json);
return { success: true, value };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error(String(error))
};
}
}
// Option 类型
type Option<T> = Some<T> | None;
interface Some<T> {
readonly _tag: 'Some';
readonly value: T;
}
interface None {
readonly _tag: 'None';
}
function Some<T>(value: T): Some<T> {
return { _tag: 'Some', value };
}
const None: None = { _tag: 'None' };
// Either 类型
type Either<L, R> = Left<L> | Right<R>;
interface Left<L> {
readonly _tag: 'Left';
readonly left: L;
}
interface Right<R> {
readonly _tag: 'Right';
readonly right: R;
}
function Left<L>(left: L): Left<L> {
return { _tag: 'Left', left };
}
function Right<R>(right: R): Right<R> {
return { _tag: 'Right', right };
}
// 使用示例
function divide(a: number, b: number): Either<string, number> {
if (b === 0) {
return Left("Cannot divide by zero");
}
return Right(a / b);
}
const result = divide(10, 2);
if (result._tag === 'Right') {
console.log('Result:', result.right);
} else {
console.error('Error:', result.left);
}5.2 断言函数
typescript
// 类型断言函数
function assertIsString(value: any): asserts value is string {
if (typeof value !== 'string') {
throw new Error(`Expected string, got ${typeof value}`);
}
}
function assertIsNumber(value: any): asserts value is number {
if (typeof value !== 'number') {
throw new Error(`Expected number, got ${typeof value}`);
}
}
// 条件断言
function assert(condition: any, message?: string): asserts condition {
if (!condition) {
throw new Error(message || 'Assertion failed');
}
}
// 使用断言
function processInput(input: any) {
assertIsString(input);
// 这里 input 被推断为 string 类型
console.log(input.toUpperCase());
}
// 自定义错误类型
class ValidationError extends Error {
constructor(
public field: string,
message: string
) {
super(message);
this.name = 'ValidationError';
}
}
class NetworkError extends Error {
constructor(
public status: number,
message: string
) {
super(message);
this.name = 'NetworkError';
}
}
type AppError = ValidationError | NetworkError;
function handleError(error: AppError) {
if (error instanceof ValidationError) {
console.error(`Validation error in ${error.field}: ${error.message}`);
} else if (error instanceof NetworkError) {
console.error(`Network error ${error.status}: ${error.message}`);
}
}6. 性能优化与最佳实践
6.1 类型性能优化
typescript
// 1. 避免过度使用 any
// ❌ 不好的做法
function processData(data: any): any {
// ...
}
// ✅ 好的做法
function processData<T>(data: T): T {
// ...
}
// 2. 使用类型别名而不是接口(对于简单类型)
// ✅ 更高效
type Point = {
x: number;
y: number;
};
// 3. 避免深度嵌套的类型
// ❌ 不好的做法
type DeepNestedType = {
level1: {
level2: {
level3: {
value: string;
};
};
};
};
// ✅ 好的做法
type Level3 = { value: string };
type Level2 = { level3: Level3 };
type Level1 = { level2: Level2 };
type FlatType = { level1: Level1 };
// 4. 使用 const 断言
// ✅ 更好的类型推断
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3
} as const;
// 5. 避免不必要的泛型约束
// ❌ 不必要的约束
function identity<T extends any>(arg: T): T {
return arg;
}
// ✅ 简化的泛型
function identity<T>(arg: T): T {
return arg;
}6.2 代码组织最佳实践
typescript
// 1. 模块组织
// types/ 目录结构
// types/
// ├── index.ts // 导出所有类型
// ├── api.ts // API 相关类型
// ├── components.ts // 组件相关类型
// └── utils.ts // 工具类型
// 2. 使用 barrel exports
// types/index.ts
export * from './api';
export * from './components';
export * from './utils';
export * from './enums';
// 3. 避免全局类型污染
// 使用模块而不是全局声明
declare global {
// ❌ 避免这样做
interface Window {
myApp: any;
}
}
// ✅ 更好的做法
export interface AppConfig {
// 具体类型定义
}
// 4. 使用命名空间组织内部类型
namespace Internal {
export type Config = {
debug: boolean;
version: string;
};
export type State = {
isLoading: boolean;
data: any;
};
}
// 5. 文档注释
/**
* 用户信息接口
* @interface User
* @property {string} id - 用户唯一标识
* @property {string} name - 用户姓名
* @property {string} email - 用户邮箱
* @property {Date} createdAt - 创建时间
*/
interface User {
/** 用户唯一标识 */
id: string;
/** 用户姓名 */
name: string;
/** 用户邮箱 */
email: string;
/** 创建时间 */
createdAt: Date;
}6.3 编译优化配置
json
{
"compilerOptions": {
/* 性能优化相关配置 */
"skipLibCheck": true, // 跳过库文件的类型检查
"skipDefaultLibCheck": true, // 跳过默认库文件的类型检查
"incremental": true, // 启用增量编译
"tsBuildInfoFile": ".tsbuildinfo", // 构建信息文件位置
"composite": true, // 启用项目引用
"disableSourceOfProjectReferenceRedirect": true,
"disableSolutionSearching": true,
/* 输出优化 */
"removeComments": true, // 移除注释
"noEmitOnError": true, // 出错时不生成文件
"importsNotUsedAsValues": "remove", // 移除未使用的导入
/* 语言特性 */
"strict": true, // 启用所有严格检查
"noUnusedLocals": true, // 检查未使用的局部变量
"noUnusedParameters": true, // 检查未使用的参数
"noImplicitReturns": true, // 检查隐式返回
"noFallthroughCasesInSwitch": true,
/* 模块解析优化 */
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"isolatedModules": true
},
/* 文件管理 */
"include": ["src/**/*"],
"exclude": [
"node_modules",
"dist",
"build",
"coverage",
"**/*.test.ts",
"**/*.spec.ts"
],
/* 项目引用 */
"references": [
{ "path": "./common" },
{ "path": "./utils" }
]
}