TypeScript 类型系统深度解析 从基础到高级类型体操 如何在项目中实现类型安全与代码可维护性

引言:TypeScript 类型系统的重要性
TypeScript 作为 JavaScript 的超集,其核心价值在于强大的静态类型系统。它不仅能在编译期捕获大量潜在错误,还能显著提升代码的可读性、可维护性和开发体验。本文将从基础概念出发,逐步深入到高级类型体操,最后探讨如何在实际项目中落地类型安全与代码可维护性。
一、TypeScript 类型系统基础
1.1 基础类型(Primitive Types)
TypeScript 支持所有 JavaScript 的原始类型,并在此基础上增加了
void
、
null
、
undefined
、
never
等类型。
// 基础类型示例
const name: string = “Alice”;
const age: number = 25;
const isStudent: boolean = true;
const nothing: null = null;
const notDefined: undefined = undefined;
const neverValue: never = (() => { throw new Error(“error”) })();
const voidValue: void = (() => { console.log(“void”) })();
详细说明
:
string
:字符串类型,支持模板字符串
number
:数字类型,支持整数、浮点数、NaN、Infinity
boolean
:布尔值
null
和
undefined
:分别表示空值和未定义
never
:表示永远不会发生的类型(如抛出异常的函数返回值)
void
:表示没有返回值的函数返回类型
1.2 复合类型(Composite Types)
1.2.1 数组类型
// 数组类型的两种表示方式
const numbers1: number[] = [1, 2, 3];
const numbers2: Array = [1, 2, 3];

// 元组类型(Tuple)
const tuple: [string, number] = [“hello”, 42];
// tuple[2] = true; // 错误:类型“true”不可赋给类型“string | number”
1.2.2 对象类型与接口
// 接口定义
interface Person {
name: string;
age: number;
email?: string; // 可选属性
readonly id: string; // 只读属性
}

// 使用接口
const person: Person = {
name: “Alice”,
age: 25,
id: “001”
};

// person.id = “002”; // 错误:无法分配到 “id” ,因为它是只读属性
1.2.3 联合类型与交叉类型
// 联合类型(Union Types)
type ID = string | number;
const id1: ID = “abc123”;
const id2: ID = 123;

// 交叉类型(Intersection Types)
interface Employee {
employeeId: string;
department: string;
}

type Staff = Person & Employee;
const staff: Staff = {
name: “Bob”,
age: 30,
id: “002”,
employeeId: “E001”,
department: “Engineering”
};
1.3 类型推断与类型断言
1.3.1 类型推断
// TypeScript 会根据赋值自动推断类型
let inferredString = “hello”; // 推断为 string 类型
let inferredNumber = 42; // 推断为 number 类型

// 函数返回类型推断
function add(a: number, b: number) {
return a + b; // 推断返回类型为 number
}
1.3.2 类型断言
// 使用 as 语法
const someValue: any = “this is a string”;
const strLength: number = (someValue as string).length;

// 使用尖括号语法(JSX中不能使用)
const strLength2: number = (someValue).length;

// 非空断言
function getLength(value?: string) {
// 非空断言,告诉编译器 value 一定不为 undefined
return value!.length;
}
二、TypeScript 高级类型
2.1 泛型(Generics)
泛型是 TypeScript 类型系统的核心,它允许我们编写可重用的、类型安全的代码。
// 基础泛型函数
function identity(arg: T): T {
return arg;
}

// 使用泛型
const output1 = identity(“myString”);
const output2 = identity(42);
const output3 = identity(true); // 类型推断

// 泛型接口
interface ApiResponse {
data: T;
status: number;
message: string;
}

// 使用泛型接口
interface User {
id: number;
name: string;
}

const response: ApiResponse = {
data: { id: 1, name: “Alice” },
status: 200,
message: “Success”
};
2.2 条件类型(Conditional Types)
条件类型允许我们根据类型关系进行类型转换。
// 基础条件类型
type IsString = T extends string ? true : false;
type A = IsString; // true
type B = IsString; // false

// 分配条件类型(Distributive Conditional Types)
type Flatten = T extends any[] ? T[number] : T;
type C = Flatten<[1, 2, 3]>; // number
type D = Flatten; // string

// infer 关键字
type ReturnType = T extends (…args: any[]) => infer R ? R : never;
type E = ReturnType<() => string>; // string
type F = ReturnType<(x: number) => boolean>; // boolean
2.3 映射类型(Mapped Types)
映射类型允许我们从一个类型创建另一个类型。
// 基础映射类型
type Readonly = {
readonly [P in keyof T]: T[P];
};

type Optional = {
[P in keyof T]?: T[P];
};

// 使用映射类型
interface Point {
x: number;
y: number;
}

type ReadonlyPoint = Readonly;
// 等同于:{ readonly x: number; readonly y: number; }

type OptionalPoint = Optional;
// 等同于:{ x?: number; y?: number; }

// 内置映射类型
type PartialPoint = Partial; // 所有属性变为可选
type RequiredPoint = Required>; // 所有属性变为必选
type PickPoint = Pick; // 只选取 x 属性
type RecordPoint = Record<'a' | 'b', number>; // { a: number; b: number; }
2.4 模板字符串类型(Template Literal Types)
TypeScript 4.1 引入了模板字符串类型,允许在类型层面操作字符串。
// 基础模板字符串类型
type Greeting = `Hello ${string}`;
const greeting: Greeting = “Hello World”; // 正确
// const badGreeting: Greeting = “Hi World”; // 错误

// 路由字符串类型
type Route = `/api/${‘users’ | ‘posts’}/${string}`;
const userRoute: Route = “/api/users/123”;
const postRoute: Route = “/api/posts/456”;
// const invalidRoute: Route = “/api/comments/789”; // 错误

// 转换大小写
type UpperCase = Uppercase;
type LowerCase = Lowercase;
type Capitalize = Capitalize;
type Uncapitalize = Uncapitalize;

type UpperHello = UpperCase<"hello">; // “HELLO”
2.5 类型守卫与类型收窄(Type Guards & Type Narrowing)
// typeof 类型守卫
function padLeft(value: string, padding: string | number) {
if (typeof padding === “number”) {
return Array(padding + 1).join(” “) + value;
}
if (typeof padding === “string”) {
return padding + value;
}
throw new Error(`Expected string or number, got ‘${padding}’.`);
}

// instanceof 类型守卫
class Fish {
swim() { console.log(“swimming”); }
}
class Bird {
fly() { console.log(“flying”); }
}

function move(pet: Fish | Bird) {
if (pet instanceof Fish) {
pet.swim(); // pet 被收窄为 Fish
} else {
pet.fly(); // pet 被收窄为 Bird
}
}

// 自定义类型守卫
interface Cat {
meow: () => void;
}
interface Dog {
bark: () => void;
}

function isCat(pet: Cat | Dog): pet is Cat {
return (pet as Cat).meow !== undefined;
}

function makeSound(pet: Cat | Dog) {
if (isCat(pet)) {
pet.meow(); // pet 被收窄为 Cat
} else {
pet.bark(); // pet 被收窄为 Dog
}
}
三、高级类型体操(Type Gymnastics)
3.1 递归类型(Recursive Types)
// 树形结构
type Tree = {
value: T;
children?: Tree[];
};

const tree: Tree = {
value: 1,
children: [
{ value: 2 },
{
value: 3,
children: [{ value: 4 }]
}
]
};

// 深度Readonly
type DeepReadonly = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly : T[P];
};

type NestedObject = {
a: {
b: {
c: number;
};
};
};

type ReadonlyNested = DeepReadonly;
// { readonly a: { readonly b: { readonly c: number } } }
3.2 字符串操作类型(String Manipulation)
// 分割字符串
type Split =
S extends `${infer Head}${Delimiter}${infer Tail}`
? [Head, …Split]
: S extends ”
? []
: [S];

type Parts = Split<"a,b,c", ",">; // [“a”, “b”, “c”]

// 反转字符串
type Reverse =
S extends `${infer First}${infer Rest}`
? `${Reverse}${First}`
: ”;

type Reversed = Reverse<"hello">; // “olleh”

// 替换所有
type ReplaceAll =
S extends `${infer Before}${From}${infer After}`
? `${Before}${To}${ReplaceAll}`
: S;

type Replaced = ReplaceAll<"hello world", "l", "L">; // “heLLo worLd”
3.3 函数组合与柯里化类型
// 柯里化函数类型
type Curry any> =
F extends (…args: infer Args) => infer Return
? Args extends [infer First, …infer Rest]
? (arg: First) => Curry<(...args: Rest) => Return>
: Return
: never;

function curry any>(fn: F): Curry {
const expectedArgs = fn.length;
const curried = (…args: any[]) => {
if (args.length >= expectedArgs) {
return fn(…args);
} else {
return (…moreArgs: any[]) => curried(…args, …moreArgs);
}
};
return curried as Curry;
}

// 使用示例
const add = (a: number, b: number, c: number) => a + b + c;
const curriedAdd = curry(add);
const result = curriedAdd(1)(2)(3); // 6
3.4 类型级编程(Type-Level Programming)
// 计算元组长度
type Length = T[‘length’];
type TupleLength = Length<[1, 2, 3]>; // 3

// 获取数组第一个元素
type First = T extends [infer First, …any[]] ? First : never;
type FirstElement = First<[1, 2, 3]>; // 1

// 获取数组最后一个元素
type Last = T extends […any[], infer Last] ? Last : never;
type LastElement = Last<[1, 2, 3]>; // 3

// 数组去重
type Unique =
T extends [infer First, …infer Rest]
? First extends U[number]
? Unique
: Unique
: U;

type UniqueTuple = Unique<[1, 2, 2, 3, 1, 4]>; // [1, 2, 3, 4]
四、项目实践:类型安全与代码可维护性
4.1 严格的类型配置
在
tsconfig.json
中启用严格模式是实现类型安全的第一步:
{
“compilerOptions”: {
“strict”: true,
“noImplicitAny”: true,
“strictNullChecks”: true,
“strictFunctionTypes”: true,
“strictBindCallApply”: true,
“strictPropertyInitialization”: true,
“noImplicitThis”: true,
“alwaysStrict”: true,
“exactOptionalPropertyTypes”: true,
“noImplicitOverride”: true,
“noPropertyAccessFromIndexSignature”: true,
“noUnusedLocals”: true,
“noUnusedParameters”: true,
“exactOptionalPropertyTypes”: true,
“noFallthroughCasesInSwitch”: true,
“noUncheckedIndexedAccess”: true
}
}
4.2 类型声明文件(.d.ts)管理
4.2.1 全局类型声明
// types/global.d.ts
declare global {
interface Window {
myCustomAPI: {
version: string;
init: () => void;
};
}

// 扩展 Process 环境变量
namespace NodeJS {
interface ProcessEnv {
NODE_ENV: ‘development’ | ‘production’ | ‘test’;
API_URL: string;
}
}
}

export {};
4.2.2 模块类型声明
// types/custom-module.d.ts
declare module ‘my-untyped-library’ {
export interface LibraryOptions {
debug?: boolean;
timeout?: number;
}

export function init(options?: LibraryOptions): void;
export function getData(url: string): Promise;
}
4.3 类型安全的 API 调用
4.3.1 使用泛型封装 API 客户端
// api/client.ts
interface ApiResponse {
data: T;
status: number;
message: string;
error?: string;
}

class ApiClient {
private baseUrl: string;

constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}

async get(endpoint: string): Promise> {
const response = await fetch(`${this.baseUrl}${endpoint}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}

async post(endpoint: string, data: D): Promise> {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: ‘POST’,
headers: { ‘Content-Type’: ‘application/json’ },
body: JSON.stringify(data)
});
return response.json();
}
}

// 使用示例
interface User {
id: number;
name: string;
email: string;
}

const client = new ApiClient(‘https://api.example.com’);

async function fetchUser(id: number): Promise {
const response = await client.get(`/users/${id}`);
if (response.status !== 200) {
throw new Error(response.error || ‘Failed to fetch user’);
}
return response.data;
}
4.3.2 使用 Zod 进行运行时类型验证
// 安装:npm install zod
import { z } from ‘zod’;

// 定义验证模式
const UserSchema = z.object({
id: z.number().positive(),
name: z.string().min(1).max(50),
email: z.string().email(),
age: z.number().int().min(0).optional()
});

// 推断 TypeScript 类型
type User = z.infer;

// 验证函数
function validateUser(input: unknown): User {
try {
return UserSchema.parse(input);
} catch (error) {
if (error instanceof z.ZodError) {
console.error(‘Validation errors:’, error.errors);
throw new Error(‘Invalid user data’);
}
throw error;
// 4.3.2 使用 Zod 进行运行时类型验证(续)
}
}

// 使用示例
const userData = {
id: 1,
name: “Alice”,
email: “alice@example.com”,
age: 25
};

try {
const user = validateUser(userData);
console.log(‘Valid user:’, user);
} catch (error) {
console.error(‘Invalid user data’);
}

// 从 API 响应验证
async function fetchAndValidateUser(id: number): Promise {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
return validateUser(data);
}
4.4 类型安全的 Redux 状态管理
// store/types.ts
interface Todo {
id: string;
text: string;
completed: boolean;
}

interface TodoState {
todos: Todo[];
loading: boolean;
error: string | null;
}

// store/actions.ts
import { createAction, createAsyncThunk } from ‘@reduxjs/toolkit’;

// 使用 createAction 创建类型安全的 actions
export const addTodo = createAction(‘todos/add’);
export const toggleTodo = createAction(‘todos/toggle’);
export const deleteTodo = createAction(‘todos/delete’);

// 使用 createAsyncThunk 创建异步 action
export const fetchTodos = createAsyncThunk(
‘todos/fetch’,
async (_, { rejectWithValue }) => {
try {
const response = await fetch(‘/api/todos’);
if (!response.ok) {
throw new Error(‘Failed to fetch todos’);
}
const data = await response.json();
// 验证数据结构
return data.map((todo: any) => ({
id: String(todo.id),
text: String(todo.text),
completed: Boolean(todo.completed)
}));
} catch (error) {
return rejectWithValue(error instanceof Error ? error.message : ‘Unknown error’);
}
}
);

// store/slice.ts
import { createSlice, PayloadAction } from ‘@reduxjs/toolkit’;
import { TodoState } from ‘./types’;
import { fetchTodos } from ‘./actions’;

const initialState: TodoState = {
todos: [],
loading: false,
error: null
};

const todoSlice = createSlice({
name: ‘todos’,
initialState,
reducers: {
addTodo: (state, action: PayloadAction) => {
state.todos.push(action.payload);
},
toggleTodo: (state, action: PayloadAction) => {
const todo = state.todos.find(t => t.id === action.payload);
if (todo) {
todo.completed = !todo.completed;
}
},
deleteTodo: (state, action: PayloadAction) => {
state.todos = state.todos.filter(t => t.id !== action.payload);
}
},
extraReducers: (builder) => {
builder
.addCase(fetchTodos.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchTodos.fulfilled, (state, action) => {
state.loading = false;
state.todos = action.payload;
})
.addCase(fetchTodos.rejected, (state, action) => {
state.loading = false;
state.error = action.payload || ‘Failed to fetch todos’;
});
}
});

export const { addTodo, toggleTodo, deleteTodo } = todoSlice.actions;
export default todoSlice.reducer;
4.5 类型安全的组件开发(React)
// components/Button.tsx
import React from ‘react’;

// 定义组件 Props 类型
interface ButtonProps {
variant?: ‘primary’ | ‘secondary’ | ‘danger’;
size?: ‘small’ | ‘medium’ | ‘large’;
disabled?: boolean;
onClick?: (event: React.MouseEvent) => void;
children: React.ReactNode;
}

// 使用 React.FC 类型
export const Button: React.FC = ({
variant = ‘primary’,
size = ‘medium’,
disabled = false,
onClick,
children
}) => {
const className = `btn btn-${variant} btn-${size}`;

return (

);
};

// 使用示例
const App: React.FC = () => {
return (


);
};
4.6 类型安全的表单处理
// hooks/useForm.ts
import { useState, useCallback } from ‘react’;

interface FormState {
values: T;
errors: Partial>;
isValid: boolean;
}

export function useForm>(
initialValues: T,
validate?: (values: T) => Partial>
) {
const [formState, setFormState] = useState>({
values: initialValues,
errors: {},
isValid: false
});

const handleChange = useCallback((key: keyof T, value: T[typeof key]) => {
setFormState(prev => {
const newValues = { …prev.values, [key]: value };
const newErrors = validate ? validate(newValues) : {};
const isValid = Object.keys(newErrors).length === 0;

return {
values: newValues,
errors: newErrors,
isValid
};
});
}, [validate]);

const reset = useCallback(() => {
setFormState({
values: initialValues,
errors: {},
isValid: false
});
}, [initialValues]);

return {
…formState,
handleChange,
reset
};
}

// 使用示例
interface LoginForm {
email: string;
password: string;
}

const validateLogin = (values: LoginForm) => {
const errors: Partial> = {};

if (!values.email) {
errors.email = ‘Email is required’;
} else if (!/\S+@\S+\.\S+/.test(values.email)) {
errors.email = ‘Email is invalid’;
}

if (!values.password) {
errors.password = ‘Password is required’;
} else if (values.password.length < 6) { errors.password = 'Password must be at least 6 characters'; } return errors; }; const LoginFormComponent: React.FC = () => {
const { values, errors, isValid, handleChange, reset } = useForm(
{ email: ”, password: ” },
validateLogin
);

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (isValid) {
console.log(‘Form submitted:’, values);
reset();
}
};

return (

handleChange(’email’, e.target.value)}
placeholder=”Email”
/>
{errors.email && {errors.email}}
handleChange(‘password’, e.target.value)}
placeholder=”Password”
/>
{errors.password && {errors.password}}


);
};
4.7 类型安全的错误处理
// utils/result.ts
export type Result =
| { success: true; value: T }
| { success: false; error: E };

export function createSuccess(value: T): Result {
return { success: true, value };
}

export function createError(error: E): Result {
return { success: false, error };
}

// 使用 Result 类型
import { Result, createSuccess, createError } from ‘./result’;

function divide(a: number, b: number): Result {
if (b === 0) {
return createError(new Error(‘Division by zero’));
}
return createSuccess(a / b);
}

// 使用示例
const result = divide(10, 2);
if (result.success) {
console.log(‘Result:’, result.value); // 5
} else {
console.error(‘Error:’, result.error.message);
}

const result2 = divide(10, 0);
if (result2.success) {
console.log(‘Result:’, result2.value);
} else {
console.error(‘Error:’, result2.error.message); // Division by zero
}
4.8 类型守卫与验证库集成
// utils/type-guards.ts
// 常用类型守卫
export function isString(value: unknown): value is string {
return typeof value === ‘string’;
}

export function isNumber(value: unknown): value is number {
return typeof value === ‘number’;
}

export function isObject(value: unknown): value is Record {
return typeof value === ‘object’ && value !== null && !Array.isArray(value);
}

export function hasProperty(
obj: unknown,
key: K
): obj is Record {
return isObject(obj) && key in obj;
}

// 复杂对象验证
interface ApiError {
code: string;
message: string;
details?: Record;
}

export function isApiError(value: unknown): value is ApiError {
return (
hasProperty(value, ‘code’) &&
isString(value.code) &&
hasProperty(value, ‘message’) &&
isString(value.message) &&
(!hasProperty(value, ‘details’) || isObject(value.details))
);
}

// 使用示例
async function fetchData() {
try {
const response = await fetch(‘/api/data’);
const data = await response.json();
return data;
} catch (error) {
if (isApiError(error)) {
console.error(`API Error ${error.code}: ${error.message}`);
if (error.details) {
console.error(‘Details:’, error.details);
}
} else if (error instanceof Error) {
console.error(‘Error:’, error.message);
} {
console.error(‘Unknown error:’, error);
}
throw error;
}
}
4.9 类型安全的依赖注入
// di/container.ts
type Constructor = new (…args: any[]) => T;

class Container {
private services = new Map();
private singletonInstances = new Map();

register(token: string, constructor: Constructor, isSingleton = false): void {
this.services.set(token, { constructor, isSingleton });
}

resolve(token: string): T {
const service = this.services.get(token);
if (!service) {
throw new Error(`Service ${token} not registered`);
}

if (service.isSingleton) {
if (!this.singletonInstances.has(token)) {
this.singletonInstances.set(token, new service.constructor());
}
return this.singletonInstances.get(token);
}

return new service.constructor();
}
}

// 使用示例
interface Logger {
log(message: string): void;
}

class ConsoleLogger implements Logger {
log(message: string): void {
console.log(`[LOG] ${message}`);
}
}

class FileLogger implements Logger {
log(message: string): void {
// 写入文件
console.log(`[FILE] ${message}`);
}
}

class AppService {
constructor(private logger: Logger) {}

doSomething(): void {
this.logger.log(‘AppService is working’);
}
}

// 配置容器
const container = new Container();
container.register(‘Logger’, ConsoleLogger, true);
container.register(‘AppService’, AppService, false);

// 使用
const logger = container.resolve(‘Logger’);
const appService = container.resolve(‘AppService’);
appService.doSomething();
4.10 类型安全的配置管理
// config/types.ts
interface DatabaseConfig {
host: string;
port: number;
username: string;
password: string;
database: string;
}

interface ServerConfig {
port: number;
host: string;
cors: boolean;
rateLimit: {
windowMs: number;
max: number;
};
}

interface Config {
database: DatabaseConfig;
server: ServerConfig;
nodeEnv: ‘development’ | ‘production’ | ‘test’;
logLevel: ‘debug’ | ‘info’ | ‘warn’ | ‘error’;
}

// config/validator.ts
import { z } from ‘zod’;

const DatabaseConfigSchema = z.object({
host: z.string().min(1),
port: z.number().int().positive().max(65535),
username: z.string().min(1),
password: z.string().min(1),
database: z.string().min(1)
});

const ServerConfigSchema = z.object({
port: z.number().int().positive().max(65535),
host: z.string().min(1),
cors: z.boolean(),
rateLimit: z.object({
windowMs: z.number().int().positive(),
max: z.number().int().positive()
})
});

const ConfigSchema = z.object({
database: DatabaseConfigSchema,
server: ServerConfigSchema,
nodeEnv: z.enum([‘development’, ‘production’, ‘test’]),
logLevel: z.enum([‘debug’, ‘info’, ‘warn’, ‘error’])
});

export function validateConfig(rawConfig: unknown): Config {
try {
return ConfigSchema.parse(rawConfig);
} catch (error) {
if (error instanceof z.ZodError) {
const messages = error.errors.map(err =>
`${err.path.join(‘.’)}: ${err.message}`
).join(‘\n’);
throw new Error(`Invalid configuration:\n${messages}`);
}
throw error;
}
}

// config/index.ts
import { validateConfig } from ‘./validator’;
import type { Config } from ‘./types’;

// 从环境变量加载配置
const rawConfig = {
database: {
host: process.env.DB_HOST || ‘localhost’,
port: parseInt(process.env.DB_PORT || ‘5432’, 10),
username: process.env.DB_USER || ‘postgres’,
password: process.env.DB_PASSWORD || ‘password’,
database: process.env.DB_NAME || ‘myapp’
},
server: {
port: parseInt(process.env.PORT || ‘3000’, 10),
host: process.env.HOST || ‘localhost’,
cors: process.env.CORS === ‘true’,
rateLimit: {
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW || ‘900000’, 10),
max: parseInt(process.env.RATE_LIMIT_MAX || ‘100’, 10)
}
},
nodeEnv: (process.env.NODE_ENV || ‘development’) as Config[‘nodeEnv’],
logLevel: (process.env.LOG_LEVEL || ‘info’) as Config[‘logLevel’]
};

export const config = validateConfig(rawConfig);
4.11 类型安全的数据库访问
// db/types.ts
import { z } from ‘zod’;

// 用户表模型
export const UserSchema = z.object({
id: z.number().int().positive(),
email: z.string().email(),
name: z.string().min(1),
createdAt: z.date(),
updatedAt: z.date()
});

export type User = z.infer;

// 查询参数
export interface FindUserOptions {
id?: number;
email?: string;
limit?: number;
offset?: number;
}

// db/repository.ts
import { User, FindUserOptions } from ‘./types’;

export class UserRepository {
// 查找单个用户
async findById(id: number): Promise {
// 模拟数据库查询
const result = await this.query(‘SELECT * FROM users WHERE id = ?’, [id]);
return result ? this.mapToUser(result) : null;
}

// 查找多个用户
async find(options: FindUserOptions): Promise {
const conditions: string[] = [];
const params: any[] = [];

if (options.id) {
conditions.push(‘id = ?’);
params.push(options.id);
}
if (options.email) {
conditions.push(’email = ?’);
params.push(options.email);
}

const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(‘ AND ‘)}` : ”;
const limitClause = options.limit ? `LIMIT ${options.limit}` : ”;
const offsetClause = options.offset ? `OFFSET ${options.offset}` : ”;

const query = `SELECT * FROM users ${whereClause} ${limitClause} ${offsetClause}`;
const results = await this.queryAll(query, params);
return results.map(this.mapToUser);
}

// 创建用户
async create(user: Omit): Promise {
const now = new Date();
const result = await this.query(
‘INSERT INTO users (email, name, createdAt, updatedAt) VALUES (?, ?, ?, ?)’,
[user.email, user.name, now, now]
);
return {
id: result.insertId,
…user,
createdAt: now,
updatedAt: now
};
}

// 更新用户
async update(id: number, data: Partial>): Promise {
const existing = await this.findById(id);
if (!existing) return null;

const updates: string[] = [];
const params: any[] = [];

if (data.email) {
updates.push(’email = ?’);
params.push(data.email);
}
if (data.name) {
updates.push(‘name = ?’);
params.push(data.name);
}

params.push(new Date(), id); // updatedAt, id

const query = `UPDATE users SET ${updates.join(‘, ‘)}, updatedAt = ? WHERE id = ?`;
await this.query(query, params);

return this.findById(id);
}

// 删除用户
async delete(id: number): Promise {
const result = await this.query(‘DELETE FROM users WHERE id = ?’, [id]);
return result.affectedRows > 0;
}

// 私有辅助方法
private async query(sql: string, params: any[]): Promise {
// 模拟数据库驱动
console.log(‘Executing query:’, sql, params);
return { insertId: Math.floor(Math.random() * 1000), affectedRows: 1 };
}

private async queryAll(sql: string, params: any[]): Promise {
// 模拟数据库驱动
console.log(‘Executing query:’, sql, params);
return [
{ id: 1, email: ‘user1@example.com’, name: ‘User 1’, createdAt: new Date(), updatedAt: new Date() },
{ id: 2, email: ‘user2@example.com’, name: ‘User 2’, createdAt: new Date(), updatedAt: new Date() }
];
}

private mapToUser(data: any): User {
return UserSchema.parse(data);
}
}
4.12 类型安全的测试
// __tests__/user.test.ts
import { UserRepository } from ‘../db/repository’;
import { User } from ‘../db/types’;

describe(‘UserRepository’, () => {
let repo: UserRepository;

beforeEach(() => {
repo = new UserRepository();
});

it(‘should find user by id’, async () => {
const user = await repo.findById(1);

// TypeScript 确保 user 具有正确的类型
if (user) {
expect(user.id).toBe(1);
expect(user.email).toMatch(/@/);
// TypeScript 知道 user 是 User 类型,不是 null
const upperName = user.name.toUpperCase();
expect(upperName).toBe(user.name.toUpperCase());
}
});

it(‘should create user with correct type’, async () => {
const newUser = {
email: ‘test@example.com’,
name: ‘Test User’
};

const created = await repo.create(newUser);

// TypeScript 确保 created 具有所有 User 属性
expect(created.id).toBeDefined();
expect(created.createdAt).toBeInstanceOf(Date);
expect(created.updatedAt).toBeInstanceOf(Date);
});
});

// 类型安全的测试工具
interface TestScenario {
input: TInput;
expected: TOutput;
description: string;
}

function runTests(
scenarios: TestScenario[],
testFn: (input: TInput) => TOutput
): void {
scenarios.forEach(({ input, expected, description }) => {
it(description, () => {
const result = testFn(input);
expect(result).toEqual(expected);
});
});
}

// 使用示例
const addScenarios: TestScenario<[number, number], number>[] = [
{ input: [1, 2], expected: 3, description: ‘adds positive numbers’ },
{ input: [-1, 1], expected: 0, description: ‘adds negative and positive’ },
{ input: [0, 0], expected: 0, description: ‘adds zeros’ }
];

describe(‘add function’, () => {
runTests(addScenarios, ([a, b]) => a + b);
});
4.13 类型安全的构建工具配置
// build/types.ts
export interface BuildOptions {
entry: string;
output: {
path: string;
filename: string;
chunkFilename?: string;
};
externals?: Record;
plugins?: Array<{ name: string; apply: (compiler: any) => void;
}>;
optimization?: {
minimize: boolean;
splitChunks?: {
chunks: ‘all’ | ‘async’ | ‘initial’;
minSize: number;
};
};
}

// build/config.ts
import { BuildOptions } from ‘./types’;

export function createBuildConfig(env: ‘development’ | ‘production’): BuildOptions {
const isProd = env === ‘production’;

const config: BuildOptions = {
entry: ‘./src/index.ts’,
output: {
path: ‘./dist’,
filename: isProd ? ‘[name].[contenthash].js’ : ‘[name].js’,
chunkFilename: isProd ? ‘[id].[contenthash].js’ : ‘[id].js’
},
externals: isProd ? { react: ‘React’, ‘react-dom’: ‘ReactDOM’ } : {},
optimization: {
minimize: isProd,
splitChunks: {
chunks: ‘all’,
minSize: 20000
}
}
};

return config;
}
4.14 类型安全的 CI/CD 配置
// .github/workflows/types.ts
export interface WorkflowConfig {
name: string;
on: {
push?: {
branches: string[];
paths?: string[];
};
pull_request?: {
branches: string[];
types?: string[];
};
};
jobs: Record;
}

export interface Job {
‘runs-on’: string;
steps: Array<{ name: string; uses?: string; run?: string; env?: Record;
with?: Record;
}>;
env?: Record;
}

// .github/workflows/config.ts
import { WorkflowConfig } from ‘./types’;

export const ciWorkflow: WorkflowConfig = {
name: ‘CI’,
on: {
push: {
branches: [‘main’, ‘develop’],
paths: [‘src/**’, ‘tests/**’, ‘package.json’]
},
pull_request: {
branches: [‘main’],
types: [‘opened’, ‘synchronize’, ‘reopened’]
}
},
jobs: {
test: {
‘runs-on’: ‘ubuntu-latest’,
steps: [
{ name: ‘Checkout’, uses: ‘actions/checkout@v3’ },
{ name: ‘Setup Node’, uses: ‘actions/setup-node@v3’, with: { ‘node-version’: ’18’ } },
{ name: ‘Install’, run: ‘npm ci’ },
{ name: ‘Lint’, run: ‘npm run lint’ },
{ name: ‘Test’, run: ‘npm test’ },
{ name: ‘Build’, run: ‘npm run build’ }
],
env: {
NODE_ENV: ‘test’
}
}
}
};
4.15 类型安全的文档生成
// docs/types.ts
export interface ApiEndpoint {
path: string;
method: ‘GET’ | ‘POST’ | ‘PUT’ | ‘DELETE’ | ‘PATCH’;
description: string;
request?: {
body?: {
type: string;
required?: boolean;
schema?: Record;
};
params?: Array<{ name: string; type: string; description: string; }>;
};
response: {
status: number;
body: {
type: string;
schema?: Record;
};
};
errors?: Array<{ status: number; description: string; }>;
}

// docs/generator.ts
import { ApiEndpoint } from ‘./types’;

export class DocumentationGenerator {
private endpoints: ApiEndpoint[] = [];

addEndpoint(endpoint: ApiEndpoint): void {
this.endpoints.push(endpoint);
}

generateMarkdown(): string {
let markdown = ‘# API Documentation\n\n’;

this.endpoints.forEach(endpoint => {
markdown += `## ${endpoint.method} ${endpoint.path}\n\n`;
markdown += `${endpoint.description}\n\n`;

if (endpoint.request?.params) {
markdown += ‘### Parameters\n\n’;
markdown += ‘| Name | Type | Description |\n’;
markdown += ‘|——|——|————-|\n’;
endpoint.request.params.forEach(param => {
markdown += `| ${param.name} | ${param.type} | ${param.description} |\n`;
});
markdown += ‘\n’;
}

if (endpoint.request?.body) {
markdown += ‘### Request Body\n\n’;
markdown += `\`\`\`json\n${JSON.stringify(endpoint.request.body.schema, null, 2)}\n\`\`\`\n\n`;
}

markdown += ‘### Response\n\n’;
markdown += `Status: ${endpoint.response.status}\n\n`;
markdown += `\`\`\`json\n${JSON.stringify(endpoint.response.body.schema, null, 2)}\n\`\`\`\n\n`;

if (endpoint.errors) {
markdown += ‘### Error Responses\n\n’;
endpoint.errors.forEach(error => {
markdown += `- **${error.status}**: ${error.description}\n`;
});
markdown += ‘\n’;
}
});

return markdown;
}
}

// 使用示例
const docs = new DocumentationGenerator();

docs.addEndpoint({
path: ‘/api/users’,
method: ‘POST’,
description: ‘Create a new user’,
request: {
body: {
type: ‘UserInput’,
schema: {
email: ‘string’,
name: ‘string’,
password: ‘string’
}
}
},
response: {
status: 201,
body: {
type: ‘User’,
schema: {
id: ‘number’,
email: ‘string’,
name: ‘string’,
createdAt: ‘string’
}
}
},
errors: [
{ status: 400, description: ‘Invalid input’ },
{ status: 409, description: ‘Email already exists’ }
]
});

console.log(docs.generateMarkdown());
五、最佳实践与性能优化
5.1 类型性能优化
// 避免过度复杂的类型计算
// 不好的例子:深度嵌套的类型计算
type BadExample = T extends { a: infer A }
? A extends { b: infer B }
? B extends { c: infer C }
? C extends { d: infer D }
? D
: never
: never
: never
: never;

// 好的例子:扁平化类型计算
type GoodExample =
T extends { a: { b: { c: { d: infer D } } } } ? D : never;

// 使用尾递归优化
type FlattenArray =
T extends [infer First, …infer Rest]
? First extends any[]
? […FlattenArray, …FlattenArray]
: [First, …FlattenArray]
: [];

// 优化版本:限制递归深度
type FlattenArrayOptimized =
[Depth] extends [0]
? T
: T extends [infer First, …infer Rest]
? First extends any[]
? […FlattenArrayOptimized, …FlattenArrayOptimized]
: [First, …FlattenArrayOptimized]
: [];

// 递归深度计数器
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
5.2 类型声明文件管理策略
// 1. 项目内部类型统一管理
// types/index.ts
export * from ‘./api’;
export * from ‘./db’;
export * from ‘./config’;
export * from ‘./components’;

// 2. 第三方库类型声明
// types/third-party.d.ts
declare module ‘some-untyped-library’ {
export interface Options {
timeout?: number;
retries?: number;
}

export function fetchWithRetry(url: string, options?: Options): Promise;
}

// 3. 环境类型区分
// types/env.d.ts
///

declare module ‘*.vue’ {
import type { DefineComponent } from ‘vue’;
const component: DefineComponent<{}, {}, any>;
export default component;
}

// 4. 全局类型扩展
// types/global.d.ts
import { } from ‘vue’;

declare module ‘@vue/runtime-core’ {
export interface ComponentCustomProperties {
$myApi: MyApi;
}
}
5.3 类型安全的错误边界
// components/ErrorBoundary.tsx
import React, { Component, ErrorInfo, ReactNode } from ‘react’;

interface ErrorBoundaryProps {
children: ReactNode;
fallback?: ReactNode;
onError?: (error: Error, errorInfo: ErrorInfo) => void;
}

interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
}

class ErrorBoundary extends Component {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false, error: null };
}

static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { hasError: true, error };
}

componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
console.error(‘Error caught by boundary:’, error, errorInfo);
this.props.onError?.(error, errorInfo);
}

render(): ReactNode {
if (this.state.hasError) {
return this.props.fallback ?? (

Something went wrong.

{this.state.error?.toString()}

);
}

return this.props.children;
}
}

// 使用示例
const App: React.FC = () => {
return (
{
// 发送到错误监控服务
console.error(‘App Error:’, error, info);
}}
fallback={

Custom Error UI

}
>


);
};
5.4 类型安全的国际化
// i18n/types.ts
export type Locale = ‘en’ | ‘zh’ | ‘ja’ | ‘ko’;

export interface Translations {
common: {
save: string;
cancel: string;
delete: string;
edit: string;
};
user: {
title: string;
name: string;
email: string;
create: string;
update: string;
};
errors: {
required: string;
invalidEmail: string;
minLength: string;
};
}

// i18n/config.ts
import { Translations } from ‘./types’;

export const translations: Record = {
en: {
common: {
save: ‘Save’,
cancel: ‘Cancel’,
delete: ‘Delete’,
edit: ‘Edit’
},
user: {
title: ‘User Management’,
name: ‘Name’,
email: ‘Email’,
create: ‘Create User’,
update: ‘Update User’
},
errors: {
required: ‘This field is required’,
invalidEmail: ‘Invalid email address’,
minLength: ‘Must be at least {min} characters’
}
},
zh: {
common: {
save: ‘保存’,
cancel: ‘取消’,
delete: ‘删除’,
edit: ‘编辑’
},
user: {
title: ‘用户管理’,
name: ‘姓名’,
email: ‘邮箱’,
create: ‘创建用户’,
update: ‘更新用户’
},
errors: {
required: ‘此字段为必填项’,
invalidEmail: ‘邮箱格式不正确’,
minLength: ‘至少需要 {min} 个字符’
}
}
};

// i18n/hooks.ts
import { useCallback } from ‘react’;
import { useTranslation } from ‘react-i18next’;
import { Translations, Locale } from ‘./types’;

// 类型安全的翻译钩子
export function useTypedTranslation() {
const { t, i18n } = useTranslation();

const translate = useCallback(
(key: K, options?: any): Translations[K] => {
return t(key, options) as Translations[K];
},
[t]
);

return {
t: translate,
locale: i18n.language as Locale,
changeLocale: (locale: Locale) => i18n.changeLanguage(locale)
};
}
5.5 类型安全的权限系统
// auth/types.ts
export type Role = ‘admin’ | ‘editor’ | ‘viewer’ | ‘guest’;

export interface Permission {
resource: string;
action: ‘create’ | ‘read’ | ‘update’ | ‘delete’;
condition?: (user: User) => boolean;
}

export interface User {
id: string;
name: string;
roles: Role[];
permissions?: Permission[];
}

// auth/permission.ts
export class PermissionManager {
private rolePermissions: Record = {
admin: [
{ resource: ‘*’, action: ‘create’ },
{ resource: ‘*’, action: ‘read’ },
{ resource: ‘*’, action: ‘update’ },
{ resource: ‘*’, action: ‘delete’ }
],
editor: [
{ resource: ‘articles’, action: ‘create’ },
{ resource: ‘articles’, action: ‘read’ },
{ resource: ‘articles’, action: ‘update’ },
{ resource: ‘comments’, action: ‘read’ },
{ resource: ‘comments’, action: ‘update’ }
],
viewer: [
{ resource: ‘articles’, action: ‘read’ },
{ resource: ‘comments’, action: ‘read’ }
],
guest: [
{ resource: ‘articles’, action: ‘read’ }
]
};

hasPermission(user: User, resource: string, action: Permission[‘action’]): boolean {
// 检查用户自定义权限
if (user.permissions) {
const customPermission = user.permissions.find(
p => p.resource === resource && p.action === action
);
if (customPermission) {
if (customPermission.condition) {
return customPermission.condition(user);
}
return true;
}
}

// 检查角色权限
for (const role of user.roles) {
const rolePermissions = this.rolePermissions[role];
const hasRolePermission = rolePermissions.some(
p => (p.resource === ‘*’ || p.resource === resource) && p.action === action
);
if (hasRolePermission) return true;
}

return false;
}

// 类型安全的权限检查
checkPermission(
user: User,
resource: T,
action: Permission[‘action’]
): user is User & { permissions: Array } {
return this.hasPermission(user, resource, action);
}
}

// 使用示例
const manager = new PermissionManager();
const user: User = {
id: ‘1’,
name: ‘Alice’,
roles: [‘editor’]
};

if (manager.checkPermission(user, ‘articles’, ‘update’)) {
// TypeScript 知道 user 具有更新 articles 的权限
console.log(‘User can update articles’);
}
5.6 类型安全的缓存系统
// cache/types.ts
export interface CacheEntry {
value: T;
expiresAt: number;
}

export interface CacheOptions {
ttl?: number; // Time to live in milliseconds
maxSize?: number;
}

// cache/memory-cache.ts
export class MemoryCache {
private cache = new Map>();
private options: Required;

constructor(options: CacheOptions = {}) {
this.options = {
ttl: options.ttl ?? 5 * 60 * 1000, // 5 minutes
maxSize: options.maxSize ?? 100
};
}

set(key: string, value: T): void {
// 检查容量
if (this.cache.size >= this.options.maxSize) {
// 删除最旧的条目
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}

const expiresAt = Date.now() + this.options.ttl;
this.cache.set(key, { value, expiresAt });
}

get(key: string): T | undefined {
const entry = this.cache.get(key);

if (!entry) {
return undefined;
}

if (Date.now() > entry.expiresAt) {
this.cache.delete(key);
return undefined;
}

return entry.value as T;
}

delete(key: string): boolean {
return this.cache.delete(key);
}

clear(): void {
this.cache.clear();
}

// 类型安全的包装器
wrap(key: string, factory: () => T | Promise): Promise {
const cached = this.get(key);
if (cached !== undefined) {
return Promise.resolve(cached);
}

const result = factory();
if (result instanceof Promise) {
return result.then(value => {
this.set(key, value);
return value;
});
} else {
this.set(key, result);
return Promise.resolve(result);
}
}
}

// cache/decorator.ts
import ‘reflect-metadata’;

const CACHE_KEY = Symbol(‘cache’);

export function Cacheable(ttl?: number) {
return function (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
const cache = new MemoryCache({ ttl });

descriptor.value = async function (…args: any[]) {
const key = `${propertyKey}:${JSON.stringify(args)}`;
return cache.wrap(key, () => originalMethod.apply(this, args));
};

return descriptor;
};
}

// 使用示例
class DataService {
@Cacheable(60000) // 缓存60秒
async getUser(id: number) {
console.log(‘Fetching user from database…’);
// 模拟数据库查询
return { id, name: `User ${id}`, timestamp: Date.now() };
}
}

const service = new DataService();
// 第一次调用会执行方法
service.getUser(1).then(console.log);
// 第二次调用(60秒内)会返回缓存结果
service.getUser(1).then(console.log);
5.7 类型安全的事件系统
// events/types.ts
export interface EventMap {
[key: string]: (…args: any[]) => void;
}

export interface EventEmitterOptions {
captureRejections?: boolean;
}

// events/event-emitter.ts
export class TypedEventEmitter {
private listeners: { [K in keyof TEvents]?: TEvents[K][] } = {};
private captureRejections: boolean;

constructor(options: EventEmitterOptions = {}) {
this.captureRejections = options.captureRejections ?? false;
}

on(event: K, listener: TEvents[K]): this {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]!.push(listener);
return this;
}

off(event: K, listener: TEvents[K]): this {
const listeners = this.listeners[event];
if (listeners) {
const index = listeners.indexOf(listener);
if (index !== -1) {
listeners.splice(index, 1);
}
}
return this;
}

emit(event: K, …args: Parameters): boolean {
const listeners = this.listeners[event];
if (!listeners || listeners.length === 0) {
return false;
}

listeners.slice().forEach(listener => {
try {
listener(…args);
} catch (error) {
if (this.captureRejections) {
console.error(‘Error in event listener:’, error);
} else {
throw error;
}
}
});

return true;
}

once(event: K, listener: TEvents[K]): this {
const onceWrapper = ((…args: Parameters) => {
this.off(event, onceWrapper as TEvents[K]);
listener(…args);
}) as TEvents[K];

this.on(event, onceWrapper);
return this;
}
}

// 使用示例
interface AppEvents {
userLogin: (userId: string, timestamp: Date) => void;
userLogout: (userId: string) => void;
dataUpdate: (data: { id: number; value: string }) => void;
}

const emitter = new TypedEventEmitter();

emitter.on(‘userLogin’, (userId, timestamp) => {
console.log(`User ${userId} logged in at ${timestamp}`);
});

emitter.on(‘dataUpdate’, (data) => {
console.log(‘Data updated:’, data.id, data.value);
});

// 类型安全的事件发射
emitter.emit(‘userLogin’, ‘user123’, new Date());
emitter.emit(‘dataUpdate’, { id: 1, value: ‘test’ });

// 错误示例会被 TypeScript 检测到
// emitter.emit(‘userLogin’, 123); // 错误:类型不匹配
// emitter.emit(‘nonexistent’); // 错误:事件不存在
5.8 类型安全的配置热重载
// config/hot-reload.ts
import { watch, FSWatcher } from ‘chokidar’;
import { config as baseConfig, validateConfig } from ‘./index’;
import type { Config } from ‘./types’;

export class ConfigHotReloader {
private watcher: FSWatcher | null = null;
private currentConfig: Config;
private listeners: Array<(config: Config) => void> = [];

constructor(private configPath: string) {
this.currentConfig = baseConfig;
}

start(): void {
if (this.watcher) return;

this.watcher = watch(this.configPath, {
ignored: /node_modules/,
persistent: true
});

this.watcher.on(‘change’, async () => {
console.log(‘Config file changed, reloading…’);
try {
// 清除 require 缓存
delete require.cache[require.resolve(this.configPath)];

// 重新加载配置
const rawConfig = require(this.configPath).default;
const newConfig = validateConfig(rawConfig);

this.currentConfig = newConfig;
this.notifyListeners();

console.log(‘Config reloaded successfully’);
} catch (error) {
console.error(‘Failed to reload config:’, error);
}
});
}

stop(): void {
if (this.watcher) {
this.watcher.close();
this.watcher = null;
}
}

getConfig(): Config {
return this.currentConfig;
}

onChange(callback: (config: Config) => void): () => void {
this.listeners.push(callback);
return () => {
this.listeners = this.listeners.filter(l => l !== callback);
};
}

private notifyListeners(): void {
this.listeners.forEach(callback => {
try {
callback(this.currentConfig);
} catch (error) {
console.error(‘Error in config change listener:’, error);
}
});
}
}

// 使用示例
const reloader = new ConfigHotReloader(‘./config.json’);

// 监听配置变化
const unsubscribe = reloader.onChange((config) => {
console.log(‘New config:’, config.server.port);
});

reloader.start();

// 在应用中使用当前配置
const config = reloader.getConfig();
5.9 类型安全的插件系统
// plugins/types.ts
export interface PluginContext {
app: Application;
config: any;
logger: Logger;
}

export interface Plugin {
name: string;
version: string;
setup: (context: PluginContext, options: TOptions) => void | Promise;
teardown?: () => void | Promise;
// 插件可以扩展应用类型
extend?: (app: Application) => void;
}

export interface PluginRegistry {
register(plugin: T): void;
get(name: string): T | undefined;
has(name: string): boolean;
}

// plugins/manager.ts
import { Plugin, PluginContext, PluginRegistry } from ‘./types’;

export class PluginManager implements PluginRegistry {
private plugins = new Map();
private initialized = new Set();

constructor(private context: PluginContext) {}

register(plugin: T): void {
if (this.plugins.has(plugin.name)) {
throw new Error(`Plugin ${plugin.name} is already registered`);
}
this.plugins.set(plugin.name, plugin);
}

async initializeAll(): Promise {
for (const [name, plugin] of this.plugins) {
if (this.initialized.has(name)) continue;

try {
await plugin.setup(this.context);
if (plugin.extend) {
plugin.extend(this.context.app);
}
this.initialized.add(name);
this.context.logger.info(`Plugin ${name} initialized`);
} catch (error) {
this.context.logger.error(`Failed to initialize plugin ${name}:`, error);
throw error;
}
}
}

async teardownAll(): Promise {
for (const [name, plugin] of this.plugins) {
if (plugin.teardown) {
try {
await plugin.teardown();
this.context.logger.info(`Plugin ${name} torn down`);
} catch (error) {
this.context.logger.error(`Failed to teardown plugin ${name}:`, error);
}
}
}
}

get(name: string): T | undefined {
return this.plugins.get(name) as T | undefined;
}

has(name: string): boolean {
return this.plugins.has(name);
}
}

// 示例插件
interface AnalyticsPluginOptions {
trackingId: string;
anonymizeIp?: boolean;
}

const analyticsPlugin: Plugin = {
name: ‘analytics’,
version: ‘1.0.0’,
setup: (context, options) => {
context.logger.info(`Analytics plugin initialized with ID: ${options.trackingId}`);
// 初始化分析服务
},
extend: (app) => {
// 扩展应用类型
(app as any).analytics = {
track: (event: string, data: any) => {
console.log(‘Tracking:’, event, data);
}
};
}
};
5.10 类型安全的 CLI 工具
// cli/types.ts
export interface CommandOptions {
[key: string]: {
type: ‘string’ | ‘number’ | ‘boolean’;
alias?: string;
description: string;
required?: boolean;
default?: any;
};
}

export interface Command {
name: string;
description: string;
options: T;
action: (args: {
[K in keyof T]: T[K][‘type’] extends ‘number’
? number
: T[K][‘type’] extends ‘boolean’
? boolean
: string;
}) => void | Promise;
}

// cli/parser.ts
export class CommandParser {
constructor(private command: Command) {}

parse(args: string[]): {
options: { [K in keyof T]: any };
unknown: string[];
} {
const options: any = {};
const unknown: string[] = [];
let i = 0;

// 设置默认值
for (const [key, config] of Object.entries(this.command.options)) {
if (config.default !== undefined) {
options[key] = config.default;
}
}

while (i < args.length) { const arg = args[i]; if (arg.startsWith('--')) { const key = arg.slice(2); const option = this.command.options[key] || Object.values(this.command.options).find(o => o.alias === key);

if (!option) {
unknown.push(arg);
i++;
continue;
}

if (option.type === ‘boolean’) {
options[key] = true;
i++;
} else {
const value = args[i + 1];
if (!value || value.startsWith(‘–‘)) {
throw new Error(`Missing value for option: ${arg}`);
}
options[key] = option.type === ‘number’ ? parseInt(value, 10) : value;
i += 2;
}
} else {
unknown.push(arg);
i++;
}
}

// 验证必填项
for (const [key, config] of Object.entries(this.command.options)) {
if (config.required && options[key] === undefined) {
throw new Error(`Required option –${key} is missing`);
}
}

return { options, unknown };
}
}

// cli/builder.ts
import { Command, CommandOptions, CommandParser } from ‘./types’;

export class CLI {
private commands = new Map>();

command(config: Command): this {
this.commands.set(config.name, config);
return this;
}

async execute(args: string[]): Promise {
const [commandName, …commandArgs] = args;

if (!commandName || commandName === ‘–help’) {
this.showHelp();
return;
}

const command = this.commands.get(commandName);
if (!command) {
console.error(`Unknown command: ${commandName}`);
this.showHelp();
process.exit(1);
}

try {
const parser = new CommandParser(command);
const { options } = parser.parse(commandArgs);
await command.action(options);
} catch (error) {
console.error(`Error executing command ${commandName}:`, error);
process.exit(1);
}
}

private showHelp(): void {
console.log(‘Available commands:’);
for (const [name, command] of this.commands) {
console.log(` ${name} – ${command.description}`);
for (const [opt, config] of Object.entries(command.options)) {
const alias = config.alias ? `-${config.alias}, ` : ”;
console.log(` ${alias}–${opt} <${config.type}> ${config.description}`);
}
}
}
}

// 使用示例
const cli = new CLI();

cli.command({
name: ‘build’,
description: ‘Build the project’,
options: {
env: {
type: ‘string’,
alias: ‘e’,
description: ‘Environment to build for’,
required: true,
default: ‘production’
},
minify: {
type: ‘boolean’,
alias: ‘m’,
description: ‘Minify the output’,
default: true
},
analyze: {
type: ‘boolean’,
description: ‘Show bundle analysis’,
default: false
}
},
action: async (options) => {
console.log(‘Building with options:’, options);
// 执行构建逻辑
}
});

// 使用: ts-node cli.ts build –env development –no-minify –analyze
六、总结
TypeScript 类型系统是一个强大而复杂的工具,从基础的类型注解到高级的类型体操,它为开发者提供了构建类型安全、可维护应用的能力。通过本文的深度解析,我们涵盖了:
基础类型系统
:原始类型、复合类型、类型推断
高级类型特性
:泛型、条件类型、映射类型、模板字符串类型
类型体操
:递归类型、字符串操作、函数组合、类型级编程
项目实践
:从配置管理、API 调用、状态管理到组件开发的类型安全实践
最佳实践
:性能优化、错误处理、权限系统、缓存、事件系统等
关键要点
严格模式
:始终启用
strict
模式,这是类型安全的基础
运行时验证
:结合 Zod 等库,实现编译期和运行期的双重保障
类型声明管理
:合理组织
.d.ts
文件,扩展第三方库类型
泛型与类型守卫
:编写可重用、类型安全的代码
性能意识
:避免过度复杂的类型计算,注意递归深度
工具链集成
:将类型检查融入 CI/CD、测试、文档生成等流程
类型安全的价值
早期错误捕获
:在编译期发现 80% 以上的潜在错误
代码自文档化
:类型本身就是最好的文档
重构信心
:类型系统确保重构不会破坏现有功能
开发效率
:IDE 智能提示、自动补全、错误检查
团队协作
:清晰的类型定义减少沟通成本
通过在项目中系统性地应用这些技术和实践,你可以构建出高度类型安全、易于维护和扩展的应用程序。记住,类型系统不是负担,而是强大的盟友,善用它将使你的代码质量产生质的飞跃。