@qlover/create-app 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/react-app/README.en.md +257 -0
- package/dist/templates/react-app/README.md +29 -231
- package/dist/templates/react-app/config/IOCIdentifier.ts +13 -0
- package/dist/templates/react-app/docs/en/bootstrap.md +562 -0
- package/dist/templates/react-app/docs/en/development-guide.md +523 -0
- package/dist/templates/react-app/docs/en/env.md +482 -0
- package/dist/templates/react-app/docs/en/global.md +509 -0
- package/dist/templates/react-app/docs/en/i18n.md +268 -0
- package/dist/templates/react-app/docs/en/index.md +173 -0
- package/dist/templates/react-app/docs/en/ioc.md +424 -0
- package/dist/templates/react-app/docs/en/project-structure.md +434 -0
- package/dist/templates/react-app/docs/en/request.md +425 -0
- package/dist/templates/react-app/docs/en/router.md +404 -0
- package/dist/templates/react-app/docs/en/store.md +321 -0
- package/dist/templates/react-app/docs/en/theme.md +424 -0
- package/dist/templates/react-app/docs/en/typescript-guide.md +473 -0
- package/dist/templates/react-app/docs/zh/bootstrap.md +562 -0
- package/dist/templates/react-app/docs/zh/development-guide.md +523 -0
- package/dist/templates/react-app/docs/zh/env.md +479 -0
- package/dist/templates/react-app/docs/zh/global.md +511 -0
- package/dist/templates/react-app/docs/zh/i18n.md +268 -0
- package/dist/templates/react-app/docs/zh/index.md +173 -0
- package/dist/templates/react-app/docs/zh/ioc.md +422 -0
- package/dist/templates/react-app/docs/zh/project-structure.md +434 -0
- package/dist/templates/react-app/docs/zh/request.md +429 -0
- package/dist/templates/react-app/docs/zh/router.md +408 -0
- package/dist/templates/react-app/docs/zh/store.md +321 -0
- package/dist/templates/react-app/docs/zh/theme.md +424 -0
- package/dist/templates/react-app/docs/zh/typescript-guide.md +473 -0
- package/dist/templates/react-app/package.json +2 -2
- package/dist/templates/react-app/src/base/apis/AiApi.ts +10 -5
- package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
- package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +1 -1
- package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +10 -17
- package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
- package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +2 -1
- package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +7 -5
- package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -2
- package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +33 -0
- package/dist/templates/react-app/src/base/cases/RequestLogger.ts +1 -1
- package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +2 -2
- package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +1 -1
- package/dist/templates/react-app/src/base/services/RouteService.ts +5 -2
- package/dist/templates/react-app/src/base/services/UserService.ts +8 -10
- package/dist/templates/react-app/src/core/IOC.ts +73 -83
- package/dist/templates/react-app/src/core/bootstraps/BootstrapApp.ts +52 -4
- package/dist/templates/react-app/src/core/bootstraps/{index.ts → BootstrapsRegistry.ts} +2 -3
- package/dist/templates/react-app/src/core/registers/IocRegisterImpl.ts +25 -0
- package/dist/templates/react-app/src/core/registers/RegisterCommon.ts +11 -17
- package/dist/templates/react-app/src/core/registers/RegisterControllers.ts +10 -4
- package/dist/templates/react-app/src/core/registers/RegisterGlobals.ts +6 -15
- package/dist/templates/react-app/src/main.tsx +2 -5
- package/dist/templates/react-app/src/styles/css/antd-themes/dark.css +3 -1
- package/dist/templates/react-app/src/styles/css/antd-themes/index.css +1 -1
- package/dist/templates/react-app/src/styles/css/antd-themes/pink.css +6 -1
- package/dist/templates/react-app/src/styles/css/page.css +1 -1
- package/dist/templates/react-app/src/uikit/controllers/JSONStorageController.ts +1 -1
- package/dist/templates/react-app/tsconfig.app.json +2 -1
- package/dist/templates/react-app/tsconfig.node.json +2 -1
- package/package.json +2 -2
- package/dist/templates/react-app/src/base/port/ApiTransactionInterface.ts +0 -7
- package/dist/templates/react-app/src/base/port/RequestCatcherInterface.ts +0 -12
- package/dist/templates/react-app/src/core/bootstrap.ts +0 -58
- package/dist/templates/react-app/src/core/registers/RegisterApi.ts +0 -5
- package/dist/templates/react-app/src/core/registers/index.ts +0 -32
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
# TypeScript Development Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This guide introduces TypeScript usage standards in the project, emphasizing three programming paradigms:
|
|
6
|
+
|
|
7
|
+
- Object-Oriented Programming (OOP)
|
|
8
|
+
- Interface-based Programming
|
|
9
|
+
- Configuration-based Programming
|
|
10
|
+
|
|
11
|
+
## Programming Paradigms
|
|
12
|
+
|
|
13
|
+
### 1. Object-Oriented Programming (OOP)
|
|
14
|
+
|
|
15
|
+
In the project, we extensively use object-oriented concepts to organize code, primarily manifested in:
|
|
16
|
+
|
|
17
|
+
#### Class Design
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Base class design
|
|
21
|
+
abstract class StoreInterface<T extends StoreStateInterface> {
|
|
22
|
+
protected state: T;
|
|
23
|
+
|
|
24
|
+
constructor(initialState: T) {
|
|
25
|
+
this.state = initialState;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
abstract setState(state: Partial<T>): void;
|
|
29
|
+
|
|
30
|
+
getState(): T {
|
|
31
|
+
return this.state;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Concrete implementation
|
|
36
|
+
@injectable()
|
|
37
|
+
class UserStore extends StoreInterface<UserState> {
|
|
38
|
+
constructor() {
|
|
39
|
+
super({
|
|
40
|
+
user: null,
|
|
41
|
+
loading: false
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setState(state: Partial<UserState>): void {
|
|
46
|
+
this.state = { ...this.state, ...state };
|
|
47
|
+
this.notify();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private notify(): void {
|
|
51
|
+
// Notify observers
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Inheritance and Polymorphism
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// Base service interface
|
|
60
|
+
interface ServiceInterface {
|
|
61
|
+
initialize(): Promise<void>;
|
|
62
|
+
destroy(): void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Abstract base class
|
|
66
|
+
abstract class BaseService implements ServiceInterface {
|
|
67
|
+
abstract initialize(): Promise<void>;
|
|
68
|
+
|
|
69
|
+
destroy(): void {
|
|
70
|
+
// Common cleanup logic
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Concrete service implementation
|
|
75
|
+
class UserService extends BaseService {
|
|
76
|
+
async initialize(): Promise<void> {
|
|
77
|
+
// User service initialization logic
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Extended specific methods
|
|
81
|
+
async login(): Promise<void> {
|
|
82
|
+
// Login logic
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. Interface-based Programming
|
|
88
|
+
|
|
89
|
+
The project emphasizes using interfaces to define contracts, achieving loose coupling:
|
|
90
|
+
|
|
91
|
+
#### Interface Definition
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// Define interface contract
|
|
95
|
+
interface StorageInterface<T> {
|
|
96
|
+
get(key: string): T | null;
|
|
97
|
+
set(key: string, value: T): void;
|
|
98
|
+
remove(key: string): void;
|
|
99
|
+
clear(): void;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Interface implementation
|
|
103
|
+
class LocalStorage<T> implements StorageInterface<T> {
|
|
104
|
+
get(key: string): T | null {
|
|
105
|
+
const value = localStorage.getItem(key);
|
|
106
|
+
return value ? JSON.parse(value) : null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
set(key: string, value: T): void {
|
|
110
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
remove(key: string): void {
|
|
114
|
+
localStorage.removeItem(key);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
clear(): void {
|
|
118
|
+
localStorage.clear();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### Dependency Injection
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
// Service interface
|
|
127
|
+
interface UserServiceInterface {
|
|
128
|
+
getCurrentUser(): User | null;
|
|
129
|
+
updateProfile(data: UserProfile): Promise<void>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Service implementation
|
|
133
|
+
@injectable()
|
|
134
|
+
class UserService implements UserServiceInterface {
|
|
135
|
+
constructor(
|
|
136
|
+
@inject('StorageService') private storage: StorageInterface<User>,
|
|
137
|
+
@inject('ApiService') private api: ApiInterface
|
|
138
|
+
) {}
|
|
139
|
+
|
|
140
|
+
getCurrentUser(): User | null {
|
|
141
|
+
return this.storage.get('currentUser');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async updateProfile(data: UserProfile): Promise<void> {
|
|
145
|
+
await this.api.put('/user/profile', data);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 3. Configuration-based Programming
|
|
151
|
+
|
|
152
|
+
The project adopts a configuration-driven approach to manage features:
|
|
153
|
+
|
|
154
|
+
#### Configuration Definition
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// Configuration interface
|
|
158
|
+
interface AppConfig {
|
|
159
|
+
api: {
|
|
160
|
+
baseUrl: string;
|
|
161
|
+
timeout: number;
|
|
162
|
+
retries: number;
|
|
163
|
+
};
|
|
164
|
+
auth: {
|
|
165
|
+
tokenKey: string;
|
|
166
|
+
tokenPrefix: string;
|
|
167
|
+
expiresIn: number;
|
|
168
|
+
};
|
|
169
|
+
theme: {
|
|
170
|
+
defaultTheme: 'light' | 'dark';
|
|
171
|
+
enableUserTheme: boolean;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Configuration implementation
|
|
176
|
+
const appConfig: AppConfig = {
|
|
177
|
+
api: {
|
|
178
|
+
baseUrl: process.env.API_BASE_URL || '/api',
|
|
179
|
+
timeout: 5000,
|
|
180
|
+
retries: 3
|
|
181
|
+
},
|
|
182
|
+
auth: {
|
|
183
|
+
tokenKey: 'auth_token',
|
|
184
|
+
tokenPrefix: 'Bearer',
|
|
185
|
+
expiresIn: 7200
|
|
186
|
+
},
|
|
187
|
+
theme: {
|
|
188
|
+
defaultTheme: 'light',
|
|
189
|
+
enableUserTheme: true
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### Configuration-driven
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// Configuration-driven feature implementation
|
|
198
|
+
@injectable()
|
|
199
|
+
class ApiService {
|
|
200
|
+
constructor(
|
|
201
|
+
@inject('AppConfig') private config: AppConfig,
|
|
202
|
+
@inject('HttpClient') private http: HttpClient
|
|
203
|
+
) {
|
|
204
|
+
// Initialize service using configuration
|
|
205
|
+
this.http.setBaseUrl(config.api.baseUrl);
|
|
206
|
+
this.http.setTimeout(config.api.timeout);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async request<T>(options: RequestOptions): Promise<T> {
|
|
210
|
+
let retries = this.config.api.retries;
|
|
211
|
+
|
|
212
|
+
while (retries > 0) {
|
|
213
|
+
try {
|
|
214
|
+
return await this.http.request(options);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
retries--;
|
|
217
|
+
if (retries === 0) throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Type System Usage
|
|
225
|
+
|
|
226
|
+
### 1. Generics
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Generic interface
|
|
230
|
+
interface Repository<T> {
|
|
231
|
+
findById(id: string): Promise<T>;
|
|
232
|
+
findAll(): Promise<T[]>;
|
|
233
|
+
create(data: Omit<T, 'id'>): Promise<T>;
|
|
234
|
+
update(id: string, data: Partial<T>): Promise<T>;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Generic class
|
|
238
|
+
class ApiRepository<T> implements Repository<T> {
|
|
239
|
+
constructor(private endpoint: string) {}
|
|
240
|
+
|
|
241
|
+
async findById(id: string): Promise<T> {
|
|
242
|
+
return api.get(`${this.endpoint}/${id}`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ... other method implementations
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### 2. Type Utilities
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
// Type mapping
|
|
253
|
+
type Nullable<T> = { [P in keyof T]: T[P] | null };
|
|
254
|
+
|
|
255
|
+
// Conditional types
|
|
256
|
+
type ArrayType<T> = T extends Array<infer U> ? U : never;
|
|
257
|
+
|
|
258
|
+
// Utility types
|
|
259
|
+
type PartialDeep<T> = {
|
|
260
|
+
[P in keyof T]?: T[P] extends object ? PartialDeep<T[P]> : T[P];
|
|
261
|
+
};
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 3. Decorators
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
// Method decorator
|
|
268
|
+
function Cached(ttl: number = 3600) {
|
|
269
|
+
return function (
|
|
270
|
+
target: any,
|
|
271
|
+
propertyKey: string,
|
|
272
|
+
descriptor: PropertyDescriptor
|
|
273
|
+
) {
|
|
274
|
+
const original = descriptor.value;
|
|
275
|
+
const cache = new Map();
|
|
276
|
+
|
|
277
|
+
descriptor.value = async function (...args: any[]) {
|
|
278
|
+
const key = JSON.stringify(args);
|
|
279
|
+
if (cache.has(key)) {
|
|
280
|
+
const { value, timestamp } = cache.get(key);
|
|
281
|
+
if (Date.now() - timestamp < ttl * 1000) {
|
|
282
|
+
return value;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const result = await original.apply(this, args);
|
|
287
|
+
cache.set(key, { value: result, timestamp: Date.now() });
|
|
288
|
+
return result;
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Using decorator
|
|
294
|
+
class UserService {
|
|
295
|
+
@Cached(1800)
|
|
296
|
+
async getUserProfile(id: string): Promise<UserProfile> {
|
|
297
|
+
return this.api.get(`/users/${id}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Best Practices
|
|
303
|
+
|
|
304
|
+
### 1. Type Definitions
|
|
305
|
+
|
|
306
|
+
- Use interface for object structures
|
|
307
|
+
- Use type for union types and utility types
|
|
308
|
+
- Prefer readonly to ensure immutability
|
|
309
|
+
- Use optional properties judiciously
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
// Good practices
|
|
313
|
+
interface UserProfile {
|
|
314
|
+
readonly id: string;
|
|
315
|
+
name: string;
|
|
316
|
+
email: string;
|
|
317
|
+
avatar?: string;
|
|
318
|
+
preferences: Readonly<UserPreferences>;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Practices to avoid
|
|
322
|
+
interface BadUserProfile {
|
|
323
|
+
[key: string]: any; // Avoid using index signatures
|
|
324
|
+
data: any; // Avoid using any
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### 2. Error Handling
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
// Custom error class
|
|
332
|
+
class ApiError extends Error {
|
|
333
|
+
constructor(
|
|
334
|
+
public code: string,
|
|
335
|
+
message: string,
|
|
336
|
+
public data?: any
|
|
337
|
+
) {
|
|
338
|
+
super(message);
|
|
339
|
+
this.name = 'ApiError';
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Type guard
|
|
344
|
+
function isApiError(error: unknown): error is ApiError {
|
|
345
|
+
return error instanceof ApiError;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Error handling
|
|
349
|
+
try {
|
|
350
|
+
await api.request();
|
|
351
|
+
} catch (error) {
|
|
352
|
+
if (isApiError(error)) {
|
|
353
|
+
handleApiError(error);
|
|
354
|
+
} else {
|
|
355
|
+
handleUnknownError(error);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 3. Asynchronous Handling
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
// Async result type
|
|
364
|
+
interface AsyncResult<T, E = Error> {
|
|
365
|
+
data: T | null;
|
|
366
|
+
error: E | null;
|
|
367
|
+
loading: boolean;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Async operation wrapper
|
|
371
|
+
async function asyncWrapper<T, E = Error>(
|
|
372
|
+
promise: Promise<T>
|
|
373
|
+
): Promise<AsyncResult<T, E>> {
|
|
374
|
+
try {
|
|
375
|
+
const data = await promise;
|
|
376
|
+
return { data, error: null, loading: false };
|
|
377
|
+
} catch (error) {
|
|
378
|
+
return { data: null, error: error as E, loading: false };
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Development Tools Configuration
|
|
384
|
+
|
|
385
|
+
### 1. TSConfig Configuration
|
|
386
|
+
|
|
387
|
+
```json
|
|
388
|
+
{
|
|
389
|
+
"compilerOptions": {
|
|
390
|
+
"target": "ES2020",
|
|
391
|
+
"module": "ESNext",
|
|
392
|
+
"strict": true,
|
|
393
|
+
"esModuleInterop": true,
|
|
394
|
+
"skipLibCheck": true,
|
|
395
|
+
"forceConsistentCasingInFileNames": true,
|
|
396
|
+
"experimentalDecorators": true,
|
|
397
|
+
"emitDecoratorMetadata": true
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### 2. ESLint Configuration
|
|
403
|
+
|
|
404
|
+
```json
|
|
405
|
+
{
|
|
406
|
+
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
|
407
|
+
"rules": {
|
|
408
|
+
"@typescript-eslint/explicit-function-return-type": "error",
|
|
409
|
+
"@typescript-eslint/no-explicit-any": "error",
|
|
410
|
+
"@typescript-eslint/no-unused-vars": "error"
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Debugging Techniques
|
|
416
|
+
|
|
417
|
+
### 1. Type Assertions
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
// Type assertion
|
|
421
|
+
function processValue(value: unknown) {
|
|
422
|
+
if (typeof value === 'string') {
|
|
423
|
+
return value.toUpperCase();
|
|
424
|
+
}
|
|
425
|
+
return String(value);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Type narrowing
|
|
429
|
+
function isString(value: unknown): value is string {
|
|
430
|
+
return typeof value === 'string';
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### 2. Debugging Tools
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
// Type checking
|
|
438
|
+
type Debug<T> = {
|
|
439
|
+
[P in keyof T]: T[P];
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
// Runtime type checking
|
|
443
|
+
function assertType<T>(value: unknown, message?: string): asserts value is T {
|
|
444
|
+
if (!isValidType<T>(value)) {
|
|
445
|
+
throw new TypeError(message || 'Type assertion failed');
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## Performance Optimization
|
|
451
|
+
|
|
452
|
+
### 1. Type Optimization
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
// Use type caching
|
|
456
|
+
type CachedType<T> = T extends Function ? T : Readonly<T>;
|
|
457
|
+
|
|
458
|
+
// Avoid excessive use of generics
|
|
459
|
+
type SimpleType = string | number;
|
|
460
|
+
type ComplexType<T> = T extends SimpleType ? T : never;
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### 2. Compilation Optimization
|
|
464
|
+
|
|
465
|
+
- Use project references
|
|
466
|
+
- Enable incremental compilation
|
|
467
|
+
- Optimize type imports
|
|
468
|
+
|
|
469
|
+
## Reference Resources
|
|
470
|
+
|
|
471
|
+
- [TypeScript Official Documentation](https://www.typescriptlang.org/docs/)
|
|
472
|
+
- [TypeScript Design Patterns](https://refactoring.guru/design-patterns/typescript)
|
|
473
|
+
- [Clean Code TypeScript](https://github.com/labs42io/clean-code-typescript)
|