积分系统:让AI创作更灵活、更经济
Showme AI采用创新的积分制付费模式,让用户可以根据实际需求灵活消费,避免传统订阅制的浪费,真正实现"用多少,付多少"的理想体验。
积分套餐设计理念
四种套餐,满足不同需求
我们精心设计了四种积分套餐,覆盖从初学者到专业创作者的所有需求:
{ "compilerOptions": { "strict": true, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noUncheckedIndexedAccess": true } }
Path Mapping for Clean Imports
Configure path mapping to avoid relative import hell:
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"], "@/components/*": ["src/components/*"], "@/utils/*": ["src/utils/*"], "@/types/*": ["src/types/*"] } } }
Type Definition Best Practices
1. Use Interfaces for Object Shapes
// ✅ Good: Clear interface definition interface User { readonly id: string; name: string; email: string; createdAt: Date; preferences?: UserPreferences; } interface UserPreferences { theme: 'light' | 'dark'; notifications: boolean; language: string; }
2. Leverage Union Types for Flexibility
// ✅ Good: Descriptive union types type Status = 'pending' | 'approved' | 'rejected'; type Theme = 'light' | 'dark' | 'auto'; // ✅ Good: Discriminated unions type ApiResponse<T> = | { success: true; data: T } | { success: false; error: string };
3. Use Generic Types for Reusability
// ✅ Good: Reusable generic interface interface ApiClient<T> { get(id: string): Promise<T>; create(data: Omit<T, 'id'>): Promise<T>; update(id: string, data: Partial<T>): Promise<T>; delete(id: string): Promise<void>; } // Usage const userClient: ApiClient<User> = new UserApiClient(); const postClient: ApiClient<Post> = new PostApiClient();
Advanced Type Patterns
1. Utility Types for Transformation
// ✅ Good: Using utility types type CreateUserRequest = Omit<User, 'id' | 'createdAt'>; type UpdateUserRequest = Partial<Pick<User, 'name' | 'email'>>; type UserSummary = Pick<User, 'id' | 'name' | 'email'>;
2. Conditional Types for Complex Logic
// ✅ Good: Conditional types for API responses type ApiEndpoint<T extends string> = T extends `${infer Method} ${infer Path}` ? Method extends 'GET' ? { method: 'GET'; path: Path; body?: never } : { method: Method; path: Path; body: unknown } : never; type GetUsers = ApiEndpoint<'GET /users'>; // { method: 'GET'; path: '/users'; body?: never } type CreateUser = ApiEndpoint<'POST /users'>; // { method: 'POST'; path: '/users'; body: unknown }
3. Mapped Types for Consistency
// ✅ Good: Mapped types for form handling type FormState<T> = { [K in keyof T]: { value: T[K]; error?: string; touched: boolean; }; }; type UserFormState = FormState<CreateUserRequest>;
Error Handling Patterns
1. Result Pattern for Error Handling
type Result<T, E = Error> = | { success: true; data: T } | { success: false; error: E }; class UserService { async getUser(id: string): Promise<Result<User, 'NOT_FOUND' | 'NETWORK_ERROR'>> { try { const user = await this.apiClient.get(id); return { success: true, data: user }; } catch (error) { if (error.status === 404) { return { success: false, error: 'NOT_FOUND' }; } return { success: false, error: 'NETWORK_ERROR' }; } } }
2. Custom Error Types
abstract class AppError extends Error { abstract readonly code: string; abstract readonly statusCode: number; } class ValidationError extends AppError { readonly code = 'VALIDATION_ERROR'; readonly statusCode = 400; constructor(public field: string, message: string) { super(`Validation failed for ${field}: ${message}`); } } class NotFoundError extends AppError { readonly code = 'NOT_FOUND'; readonly statusCode = 404; constructor(resource: string, id: string) { super(`${resource} with id ${id} not found`); } }
Performance Optimization
1. Type-Only Imports
// ✅ Good: Type-only imports import type { User, UserPreferences } from './types'; import { validateUser } from './validators'; // ✅ Good: Mixed imports import { type ApiResponse, fetchData } from './api';
2. Lazy Type Loading
// ✅ Good: Lazy loading for large types type LazyUserDetails = () => Promise<import('./user-details').UserDetails>; class UserManager { async getUserDetails(id: string): Promise<Awaited<ReturnType<LazyUserDetails>>> { const { UserDetails } = await import('./user-details'); return new UserDetails(id); } }
Testing with TypeScript
1. Type-Safe Test Utilities
// ✅ Good: Type-safe test helpers function createMockUser(overrides: Partial<User> = {}): User { return { id: 'test-id', name: 'Test User', email: '[email protected]', createdAt: new Date(), ...overrides, }; } // ✅ Good: Type-safe API mocking type MockApiClient<T> = { [K in keyof ApiClient<T>]: jest.MockedFunction<ApiClient<T>[K]>; }; function createMockApiClient<T>(): MockApiClient<T> { return { get: jest.fn(), create: jest.fn(), update: jest.fn(), delete: jest.fn(), }; }
Common Pitfalls to Avoid
1. Avoid any
Type
// ❌ Bad: Using any function processData(data: any): any { return data.someProperty; } // ✅ Good: Use generics or unknown function processData<T>(data: T): T extends { someProperty: infer P } ? P : never { return (data as any).someProperty; // Type assertion when necessary } // ✅ Better: Use unknown for truly unknown data function processUnknownData(data: unknown): string { if (typeof data === 'object' && data !== null && 'someProperty' in data) { return String((data as { someProperty: unknown }).someProperty); } throw new Error('Invalid data structure'); }
2. Avoid Deep Nesting
// ❌ Bad: Deep nesting interface DeepNested { level1: { level2: { level3: { value: string; }; }; }; } // ✅ Good: Flatten with separate interfaces interface Level3Data { value: string; } interface Level2Data { level3: Level3Data; } interface Level1Data { level2: Level2Data; } interface FlattenedStructure { level1: Level1Data; }
Conclusion
Following these TypeScript best practices will help you build more maintainable, scalable, and robust applications. Remember that TypeScript is not just about adding types—it's about creating a better development experience and catching errors before they reach production.
Key takeaways:
- Start with strict configuration to catch issues early
- Use descriptive types that communicate intent
- Leverage utility types for code reuse
- Implement proper error handling patterns
- Optimize for performance with type-only imports
- Write type-safe tests for better reliability
By incorporating these practices into your development workflow, you'll write TypeScript code that not only works but is also a joy to maintain and extend.
Want to learn some about Next.js? Check out our Exploring Next.js 15 for tips.