TypeScript 高级特性:构建类型安全的现代应用
深入探索 TypeScript 的高级特性,包括泛型、装饰器、模块系统、类型推断等,帮助开发者构建更加健壮和可维护的应用程序。
2025年9月18日
DocsLib Team
TypeScriptJavaScript类型系统前端开发静态类型
TypeScript 高级特性:构建类型安全的现代应用
TypeScript 简介
TypeScript 是由 Microsoft 开发的 JavaScript 的超集,它添加了静态类型定义。TypeScript 代码会被编译成纯 JavaScript,可以在任何支持 JavaScript 的环境中运行。
TypeScript 的优势
- 静态类型检查:在编译时发现错误,而不是运行时
- 更好的 IDE 支持:智能提示、重构、导航等
- 增强的代码可读性:类型注解使代码更易理解
- 更好的重构支持:类型系统帮助安全地重构代码
- 渐进式采用:可以逐步将 JavaScript 项目迁移到 TypeScript
- 丰富的生态系统:大量的类型定义文件
基础类型系统
基本类型
// 基本类型
let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
let list: number[] = [1, 2, 3];
let tuple: [string, number] = ["hello", 10];
// 枚举
enum Color {
Red,
Green,
Blue,
}
let c: Color = Color.Green;
// Any 类型(尽量避免使用)
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;
// Void 类型
function warnUser(): void {
console.log("This is my warning message");
}
// Null 和 Undefined
let u: undefined = undefined;
let n: null = null;
// Never 类型
function error(message: string): never {
throw new Error(message);
}
// Object 类型
let obj: object = { name: "John", age: 30 };
联合类型和交叉类型
// 联合类型
type StringOrNumber = string | number;
type Theme = "light" | "dark" | "auto";
function formatValue(value: StringOrNumber): string {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toString();
}
// 交叉类型
interface Person {
name: string;
age: number;
}
interface Employee {
employeeId: string;
department: string;
}
type PersonEmployee = Person & Employee;
const employee: PersonEmployee = {
name: "John Doe",
age: 30,
employeeId: "EMP001",
department: "Engineering",
};
// 类型守卫
function isString(value: StringOrNumber): value is string {
return typeof value === "string";
}
function processValue(value: StringOrNumber) {
if (isString(value)) {
// TypeScript 知道这里 value 是 string 类型
console.log(value.toUpperCase());
} else {
// TypeScript 知道这里 value 是 number 类型
console.log(value.toFixed(2));
}
}
泛型 (Generics)
泛型是 TypeScript 最强大的特性之一,它允许我们创建可重用的组件。
基础泛型
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
// 使用泛型函数
let output1 = identity<string>("myString");
let output2 = identity<number>(100);
// 类型推断
let output3 = identity("myString"); // TypeScript 自动推断 T 为 string
// 泛型数组
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length);
return arg;
}
// 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity2<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity2;
泛型类
// 泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
constructor(zeroValue: T, addFn: (x: T, y: T) => T) {
this.zeroValue = zeroValue;
this.add = addFn;
}
}
// 使用泛型类
let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y);
let myGenericString = new GenericNumber<string>("", (x, y) => x + y);
// 数据结构示例:栈
class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
peek(): T | undefined {
return this.items[this.items.length - 1];
}
isEmpty(): boolean {
return this.items.length === 0;
}
size(): number {
return this.items.length;
}
clear(): void {
this.items = [];
}
toArray(): T[] {
return [...this.items];
}
}
// 使用栈
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
numberStack.push(3);
console.log(numberStack.peek()); // 3
console.log(numberStack.pop()); // 3
console.log(numberStack.size()); // 2
const stringStack = new Stack<string>();
stringStack.push("hello");
stringStack.push("world");
泛型约束
// 泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity2<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在我们知道 arg 有 length 属性
return arg;
}
// 使用约束
loggingIdentity2("hello"); // 字符串有 length 属性
loggingIdentity2([1, 2, 3]); // 数组有 length 属性
// loggingIdentity2(3); // 错误:number 没有 length 属性
// 在泛型约束中使用类型参数
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
let person = { name: "John", age: 30, city: "New York" };
let name = getProperty(person, "name"); // string
let age = getProperty(person, "age"); // number
// let invalid = getProperty(person, "invalid"); // 错误:参数类型不匹配
// 条件类型
type NonNullable<T> = T extends null | undefined ? never : T;
type A = NonNullable<string | null | undefined>; // string
type B = NonNullable<number | null>; // number
// 映射类型
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 PartialUser = Partial<User>;
// 使用映射类型
const user: User = { id: 1, name: "John", email: "john@example.com" };
const readonlyUser: ReadonlyUser = user;
// readonlyUser.name = "Jane"; // 错误:只读属性
const partialUser: PartialUser = { name: "Jane" }; // 只需要部分属性
高级类型操作
工具类型
// 内置工具类型示例
interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: Date;
}
// Partial<T> - 将所有属性变为可选
type PartialTodo = Partial<Todo>;
function updateTodo(todo: Todo, fieldsToUpdate: PartialTodo): Todo {
return { ...todo, ...fieldsToUpdate };
}
// Required<T> - 将所有属性变为必需
type RequiredTodo = Required<PartialTodo>;
// Readonly<T> - 将所有属性变为只读
type ReadonlyTodo = Readonly<Todo>;
// Pick<T, K> - 选择特定属性
type TodoPreview = Pick<Todo, "title" | "completed">;
const preview: TodoPreview = {
title: "Clean room",
completed: false,
};
// Omit<T, K> - 排除特定属性
type TodoWithoutId = Omit<Todo, "createdAt">;
// Record<K, T> - 创建具有特定键和值类型的对象类型
type TodoStatus = "pending" | "in-progress" | "completed";
type TodoStatusRecord = Record<TodoStatus, number>;
const statusCount: TodoStatusRecord = {
pending: 5,
"in-progress": 3,
completed: 10,
};
// Exclude<T, U> - 从联合类型中排除特定类型
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<string | number | (() => void), Function>; // string | number
// Extract<T, U> - 从联合类型中提取特定类型
type T2 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T3 = Extract<string | number | (() => void), Function>; // () => void
// ReturnType<T> - 获取函数返回类型
function createUser(name: string, age: number) {
return { name, age, id: Math.random() };
}
type User2 = ReturnType<typeof createUser>; // { name: string; age: number; id: number; }
// Parameters<T> - 获取函数参数类型
type CreateUserParams = Parameters<typeof createUser>; // [string, number]
自定义工具类型
// 深度只读
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
interface NestedObject {
a: {
b: {
c: string;
};
};
}
type ReadonlyNested = DeepReadonly<NestedObject>;
// 所有嵌套属性都是只读的
// 可空类型
type Nullable<T> = T | null;
type Optional<T> = T | undefined;
type Maybe<T> = T | null | undefined;
// 函数重载类型
type FunctionOverload<T> = T extends {
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
(...args: infer A3): infer R3;
}
? {
(...args: A1): R1;
(...args: A2): R2;
(...args: A3): R3;
}
: T extends {
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
}
? {
(...args: A1): R1;
(...args: A2): R2;
}
: T extends (...args: infer A): infer R
? (...args: A) => R
: never;
// 键值对类型
type KeyValuePair<T> = {
[K in keyof T]: {
key: K;
value: T[K];
};
}[keyof T];
type UserKeyValue = KeyValuePair<User>;
// { key: "id"; value: number; } | { key: "name"; value: string; } | { key: "email"; value: string; }
// 条件类型示例
type IsArray<T> = T extends any[] ? true : false;
type Test1 = IsArray<string[]>; // true
type Test2 = IsArray<string>; // false
// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;
type StrArrOrNumArr = ToArray<string | number>; // string[] | number[]
装饰器 (Decorators)
装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、访问符、属性或参数上。
类装饰器
// 启用装饰器支持需要在 tsconfig.json 中设置 "experimentalDecorators": true
// 简单的类装饰器
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
// 装饰器工厂
function classDecorator<T extends { new (...args: any[]): {} }>(
constructor: T
) {
return class extends constructor {
newProperty = "new property";
hello = "override";
};
}
@classDecorator
class GreeterWithDecorator {
property = "property";
hello: string;
constructor(m: string) {
this.hello = m;
}
}
// 日志装饰器
function logClass(target: any) {
console.log(`Class ${target.name} was created`);
return target;
}
@logClass
class LoggedClass {
constructor(public name: string) {}
}
方法装饰器
// 方法装饰器
function log(
target: any,
propertyName: string,
descriptor: PropertyDescriptor
) {
const method = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${propertyName} with arguments:`, args);
const result = method.apply(this, args);
console.log(`Method ${propertyName} returned:`, result);
return result;
};
}
// 性能监控装饰器
function measure(
target: any,
propertyName: string,
descriptor: PropertyDescriptor
) {
const method = descriptor.value;
descriptor.value = function (...args: any[]) {
const start = performance.now();
const result = method.apply(this, args);
const end = performance.now();
console.log(`${propertyName} took ${end - start} milliseconds`);
return result;
};
}
// 缓存装饰器
function cache(
target: any,
propertyName: string,
descriptor: PropertyDescriptor
) {
const method = descriptor.value;
const cacheMap = new Map();
descriptor.value = function (...args: any[]) {
const key = JSON.stringify(args);
if (cacheMap.has(key)) {
console.log(`Cache hit for ${propertyName}`);
return cacheMap.get(key);
}
const result = method.apply(this, args);
cacheMap.set(key, result);
console.log(`Cache miss for ${propertyName}, result cached`);
return result;
};
}
class Calculator {
@log
@measure
add(a: number, b: number): number {
return a + b;
}
@cache
fibonacci(n: number): number {
if (n <= 1) return n;
return this.fibonacci(n - 1) + this.fibonacci(n - 2);
}
}
const calc = new Calculator();
calc.add(2, 3);
calc.fibonacci(10);
calc.fibonacci(10); // 第二次调用会使用缓存
属性装饰器
// 属性装饰器
function readonly(target: any, propertyName: string) {
Object.defineProperty(target, propertyName, {
writable: false,
});
}
// 验证装饰器
function validate(validationFn: (value: any) => boolean) {
return function (target: any, propertyName: string) {
let value = target[propertyName];
const getter = () => value;
const setter = (newValue: any) => {
if (!validationFn(newValue)) {
throw new Error(`Invalid value for ${propertyName}: ${newValue}`);
}
value = newValue;
};
Object.defineProperty(target, propertyName, {
get: getter,
set: setter,
enumerable: true,
configurable: true,
});
};
}
// 格式化装饰器
function format(formatFn: (value: any) => any) {
return function (target: any, propertyName: string) {
let value = target[propertyName];
const getter = () => value;
const setter = (newValue: any) => {
value = formatFn(newValue);
};
Object.defineProperty(target, propertyName, {
get: getter,
set: setter,
enumerable: true,
configurable: true,
});
};
}
class Person {
@readonly
id: number = Math.random();
@validate((value: string) => value.length >= 2)
@format((value: string) => value.trim().toLowerCase())
name: string;
@validate((value: number) => value >= 0 && value <= 150)
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const person = new Person(" John Doe ", 30);
console.log(person.name); // "john doe"
// person.id = 123; // 错误:只读属性
// person.age = -5; // 错误:验证失败
模块系统
ES6 模块
// math.ts - 导出模块
export function add(a: number, b: number): number {
return a + b;
}
export function subtract(a: number, b: number): number {
return a - b;
}
export const PI = 3.14159;
// 默认导出
export default class Calculator {
add = add;
subtract = subtract;
}
// 类型导出
export interface MathOperation {
(a: number, b: number): number;
}
export type OperationType = 'add' | 'subtract' | 'multiply' | 'divide';
// utils.ts - 重新导出
export { add, subtract } from './math';
export { default as Calculator } from './math';
// main.ts - 导入模块
import Calculator, { add, subtract, PI, MathOperation } from './math';
import * as MathUtils from './math';
const calc = new Calculator();
console.log(calc.add(2, 3));
console.log(add(5, 3));
console.log(PI);
// 动态导入
async function loadMath() {
const mathModule = await import('./math');
return new mathModule.default();
}
命名空间
// 命名空间定义
namespace Geometry {
export interface Point {
x: number;
y: number;
}
export interface Circle {
center: Point;
radius: number;
}
export function distance(p1: Point, p2: Point): number {
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
}
export function area(circle: Circle): number {
return Math.PI * circle.radius * circle.radius;
}
// 嵌套命名空间
export namespace Shapes {
export class Rectangle {
constructor(public width: number, public height: number) {}
area(): number {
return this.width * this.height;
}
}
export class Triangle {
constructor(
public base: number,
public height: number
) {}
area(): number {
return (this.base * this.height) / 2;
}
}
}
}
// 使用命名空间
const point1: Geometry.Point = { x: 0, y: 0 };
const point2: Geometry.Point = { x: 3, y: 4 };
const circle: Geometry.Circle = { center: point1, radius: 5 };
console.log(Geometry.distance(point1, point2)); // 5
console.log(Geometry.area(circle)); // 78.54
const rect = new Geometry.Shapes.Rectangle(10, 20);
console.log(rect.area()); // 200
// 命名空间别名
import Shapes = Geometry.Shapes;
const triangle = new Shapes.Triangle(10, 15);
console.log(triangle.area()); // 75
声明文件和类型定义
声明文件
// types.d.ts - 全局类型声明
declare global {
interface Window {
myGlobalFunction: (arg: string) => void;
myGlobalVariable: number;
}
var ENV: 'development' | 'production' | 'test';
}
// 模块声明
declare module 'my-library' {
export function doSomething(arg: string): number;
export interface MyInterface {
prop: string;
}
}
// 扩展现有模块
declare module 'express' {
interface Request {
user?: {
id: string;
name: string;
};
}
}
// jQuery 类型声明示例
declare var $: {
(selector: string): {
click(handler: () => void): void;
text(value?: string): string | void;
addClass(className: string): void;
};
ajax(settings: {
url: string;
method?: string;
data?: any;
success?: (data: any) => void;
error?: (error: any) => void;
}): void;
};
// 使用声明的类型
window.myGlobalFunction('hello');
console.log(window.myGlobalVariable);
$('#myButton').click(() => {
console.log('Button clicked');
});
$.ajax({
url: '/api/data',
method: 'GET',
success: (data) => {
console.log(data);
}
});
类型断言和类型守卫
// 类型断言
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
// 或者使用尖括号语法(在 JSX 中不可用)
let strLength2: number = (<string>someValue).length;
// 非空断言
function processUser(user: User | null) {
// 我们确定 user 不为 null
console.log(user!.name);
}
// 类型守卫函数
function isString(value: any): value is string {
return typeof value === 'string';
}
function isNumber(value: any): value is number {
return typeof value === 'number';
}
function isUser(obj: any): obj is User {
return obj && typeof obj.name === 'string' && typeof obj.age === 'number';
}
// 使用类型守卫
function processValue(value: string | number | User) {
if (isString(value)) {
// TypeScript 知道 value 是 string
console.log(value.toUpperCase());
} else if (isNumber(value)) {
// TypeScript 知道 value 是 number
console.log(value.toFixed(2));
} else if (isUser(value)) {
// TypeScript 知道 value 是 User
console.log(value.name);
}
}
// in 操作符类型守卫
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
function move(pet: Bird | Fish) {
if ('fly' in pet) {
// TypeScript 知道 pet 是 Bird
pet.fly();
} else {
// TypeScript 知道 pet 是 Fish
pet.swim();
}
}
// instanceof 类型守卫
class Dog {
bark() {
console.log('Woof!');
}
}
class Cat {
meow() {
console.log('Meow!');
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
实际应用示例
API 客户端
// API 响应类型
interface ApiResponse<T> {
data: T;
status: number;
message: string;
timestamp: string;
}
interface PaginatedResponse<T> extends ApiResponse<T[]> {
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
};
}
// 用户相关类型
interface User {
id: string;
name: string;
email: string;
avatar?: string;
createdAt: string;
updatedAt: string;
}
interface CreateUserRequest {
name: string;
email: string;
password: string;
}
interface UpdateUserRequest extends Partial<Omit<User, 'id' | 'createdAt' | 'updatedAt'>> {}
// HTTP 客户端类
class HttpClient {
private baseURL: string;
private defaultHeaders: Record<string, string>;
constructor(baseURL: string, defaultHeaders: Record<string, string> = {}) {
this.baseURL = baseURL;
this.defaultHeaders = defaultHeaders;
}
private async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const url = `${this.baseURL}${endpoint}`;
const config: RequestInit = {
...options,
headers: {
'Content-Type': 'application/json',
...this.defaultHeaders,
...options.headers,
},
};
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}
async get<T>(endpoint: string): Promise<T> {
return this.request<T>(endpoint, { method: 'GET' });
}
async post<T>(endpoint: string, data: any): Promise<T> {
return this.request<T>(endpoint, {
method: 'POST',
body: JSON.stringify(data),
});
}
async put<T>(endpoint: string, data: any): Promise<T> {
return this.request<T>(endpoint, {
method: 'PUT',
body: JSON.stringify(data),
});
}
async delete<T>(endpoint: string): Promise<T> {
return this.request<T>(endpoint, { method: 'DELETE' });
}
}
// API 服务类
class UserService {
private http: HttpClient;
constructor(http: HttpClient) {
this.http = http;
}
async getUsers(page = 1, limit = 10): Promise<PaginatedResponse<User>> {
return this.http.get<PaginatedResponse<User>>(
`/users?page=${page}&limit=${limit}`
);
}
async getUserById(id: string): Promise<ApiResponse<User>> {
return this.http.get<ApiResponse<User>>(`/users/${id}`);
}
async createUser(userData: CreateUserRequest): Promise<ApiResponse<User>> {
return this.http.post<ApiResponse<User>>('/users', userData);
}
async updateUser(
id: string,
userData: UpdateUserRequest
): Promise<ApiResponse<User>> {
return this.http.put<ApiResponse<User>>(`/users/${id}`, userData);
}
async deleteUser(id: string): Promise<ApiResponse<null>> {
return this.http.delete<ApiResponse<null>>(`/users/${id}`);
}
}
// 使用示例
const httpClient = new HttpClient('https://api.example.com', {
'Authorization': 'Bearer your-token-here'
});
const userService = new UserService(httpClient);
// 使用服务
async function example() {
try {
// 获取用户列表
const usersResponse = await userService.getUsers(1, 20);
console.log('Users:', usersResponse.data);
console.log('Total:', usersResponse.pagination.total);
// 创建新用户
const newUser = await userService.createUser({
name: 'John Doe',
email: 'john@example.com',
password: 'securepassword'
});
console.log('Created user:', newUser.data);
// 更新用户
const updatedUser = await userService.updateUser(newUser.data.id, {
name: 'Jane Doe'
});
console.log('Updated user:', updatedUser.data);
} catch (error) {
console.error('Error:', error);
}
}
状态管理
// 状态管理类型定义
type ActionType = 'SET_LOADING' | 'SET_ERROR' | 'SET_DATA' | 'RESET';
interface Action<T = any> {
type: ActionType;
payload?: T;
}
interface State<T> {
data: T | null;
loading: boolean;
error: string | null;
}
// 状态管理类
class Store<T> {
private state: State<T>;
private listeners: Array<(state: State<T>) => void> = [];
constructor(initialState?: Partial<State<T>>) {
this.state = {
data: null,
loading: false,
error: null,
...initialState,
};
}
getState(): State<T> {
return { ...this.state };
}
dispatch(action: Action): void {
this.state = this.reducer(this.state, action);
this.notifyListeners();
}
subscribe(listener: (state: State<T>) => void): () => void {
this.listeners.push(listener);
// 返回取消订阅函数
return () => {
const index = this.listeners.indexOf(listener);
if (index > -1) {
this.listeners.splice(index, 1);
}
};
}
private reducer(state: State<T>, action: Action): State<T> {
switch (action.type) {
case 'SET_LOADING':
return { ...state, loading: action.payload, error: null };
case 'SET_ERROR':
return { ...state, error: action.payload, loading: false };
case 'SET_DATA':
return { ...state, data: action.payload, loading: false, error: null };
case 'RESET':
return { data: null, loading: false, error: null };
default:
return state;
}
}
private notifyListeners(): void {
this.listeners.forEach(listener => listener(this.state));
}
}
// 异步操作管理
class AsyncStore<T> extends Store<T> {
async fetchData(fetchFn: () => Promise<T>): Promise<void> {
this.dispatch({ type: 'SET_LOADING', payload: true });
try {
const data = await fetchFn();
this.dispatch({ type: 'SET_DATA', payload: data });
} catch (error) {
this.dispatch({
type: 'SET_ERROR',
payload: error instanceof Error ? error.message : 'Unknown error'
});
}
}
}
// 使用示例
interface TodoItem {
id: string;
title: string;
completed: boolean;
createdAt: Date;
}
const todoStore = new AsyncStore<TodoItem[]>();
// 订阅状态变化
const unsubscribe = todoStore.subscribe((state) => {
console.log('Todo state changed:', state);
if (state.loading) {
console.log('Loading todos...');
} else if (state.error) {
console.error('Error loading todos:', state.error);
} else if (state.data) {
console.log('Todos loaded:', state.data);
}
});
// 模拟获取数据
async function fetchTodos(): Promise<TodoItem[]> {
// 模拟 API 调用
await new Promise(resolve => setTimeout(resolve, 1000));
return [
{
id: '1',
title: 'Learn TypeScript',
completed: false,
createdAt: new Date()
},
{
id: '2',
title: 'Build a project',
completed: true,
createdAt: new Date()
}
];
}
// 使用 store
todoStore.fetchData(fetchTodos);
// 稍后取消订阅
setTimeout(() => {
unsubscribe();
}, 5000);
最佳实践
1. 类型设计原则
// ✅ 好的实践:使用具体的类型
interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
}
// ❌ 避免:过度使用 any
interface BadUser {
id: any;
name: any;
email: any;
role: any;
}
// ✅ 好的实践:使用联合类型
type Status = 'pending' | 'approved' | 'rejected';
// ✅ 好的实践:使用泛型提高复用性
interface Repository<T> {
findById(id: string): Promise<T | null>;
findAll(): Promise<T[]>;
create(entity: Omit<T, 'id'>): Promise<T>;
update(id: string, entity: Partial<T>): Promise<T>;
delete(id: string): Promise<void>;
}
// ✅ 好的实践:使用索引签名处理动态属性
interface Config {
apiUrl: string;
timeout: number;
[key: string]: string | number | boolean;
}
2. 错误处理
// 自定义错误类型
class AppError extends Error {
constructor(
message: string,
public code: string,
public statusCode: number = 500
) {
super(message);
this.name = 'AppError';
}
}
class ValidationError extends AppError {
constructor(message: string, public field: string) {
super(message, 'VALIDATION_ERROR', 400);
this.name = 'ValidationError';
}
}
// 结果类型
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
// 安全的异步函数
async function safeAsync<T>(fn: () => Promise<T>): Promise<Result<T>> {
try {
const data = await fn();
return { success: true, data };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error : new Error(String(error))
};
}
}
// 使用示例
async function fetchUserSafely(id: string): Promise<Result<User>> {
return safeAsync(async () => {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new AppError('User not found', 'USER_NOT_FOUND', 404);
}
return response.json();
});
}
// 使用结果
async function handleUser(id: string) {
const result = await fetchUserSafely(id);
if (result.success) {
console.log('User:', result.data);
} else {
console.error('Error:', result.error.message);
}
}
3. 配置和环境
// 环境配置类型
interface DatabaseConfig {
host: string;
port: number;
database: string;
username: string;
password: string;
}
interface ApiConfig {
baseUrl: string;
timeout: number;
retries: number;
}
interface AppConfig {
env: 'development' | 'staging' | 'production';
port: number;
database: DatabaseConfig;
api: ApiConfig;
features: {
enableLogging: boolean;
enableMetrics: boolean;
enableCache: boolean;
};
}
// 配置验证
function validateConfig(config: any): config is AppConfig {
return (
config &&
typeof config.env === 'string' &&
['development', 'staging', 'production'].includes(config.env) &&
typeof config.port === 'number' &&
config.database &&
typeof config.database.host === 'string' &&
typeof config.database.port === 'number'
// ... 更多验证
);
}
// 配置加载器
class ConfigLoader {
static load(): AppConfig {
const config = {
env: process.env.NODE_ENV || 'development',
port: parseInt(process.env.PORT || '3000'),
database: {
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '5432'),
database: process.env.DB_NAME || 'myapp',
username: process.env.DB_USER || 'user',
password: process.env.DB_PASS || 'password',
},
api: {
baseUrl: process.env.API_BASE_URL || 'http://localhost:3000',
timeout: parseInt(process.env.API_TIMEOUT || '5000'),
retries: parseInt(process.env.API_RETRIES || '3'),
},
features: {
enableLogging: process.env.ENABLE_LOGGING === 'true',
enableMetrics: process.env.ENABLE_METRICS === 'true',
enableCache: process.env.ENABLE_CACHE === 'true',
},
};
if (!validateConfig(config)) {
throw new Error('Invalid configuration');
}
return config;
}
}
总结
TypeScript 的高级特性为现代 JavaScript 开发提供了强大的类型安全保障和开发体验。通过掌握泛型、装饰器、高级类型操作、模块系统等特性,开发者可以构建更加健壮、可维护和可扩展的应用程序。
关键要点
- 类型安全:利用 TypeScript 的类型系统在编译时捕获错误
- 代码复用:使用泛型和高级类型创建可重用的组件
- 开发体验:享受更好的 IDE 支持和代码提示
- 渐进式采用:可以逐步将现有 JavaScript 项目迁移到 TypeScript
- 生态系统:利用丰富的类型定义文件和社区资源
掌握这些高级特性,你将能够充分发挥 TypeScript 的威力,构建出色的现代 Web 应用程序。