积分系统:让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.