@su-record/vibe 2.7.6 → 2.7.9

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.
Files changed (69) hide show
  1. package/dist/cli/commands/init.d.ts +10 -0
  2. package/dist/cli/commands/init.d.ts.map +1 -1
  3. package/dist/cli/commands/init.js +78 -2
  4. package/dist/cli/commands/init.js.map +1 -1
  5. package/dist/cli/commands/update.d.ts.map +1 -1
  6. package/dist/cli/commands/update.js +17 -2
  7. package/dist/cli/commands/update.js.map +1 -1
  8. package/dist/cli/postinstall/codex-agents.d.ts +12 -0
  9. package/dist/cli/postinstall/codex-agents.d.ts.map +1 -0
  10. package/dist/cli/postinstall/codex-agents.js +51 -0
  11. package/dist/cli/postinstall/codex-agents.js.map +1 -0
  12. package/dist/cli/postinstall/codex-instruction.d.ts +10 -0
  13. package/dist/cli/postinstall/codex-instruction.d.ts.map +1 -0
  14. package/dist/cli/postinstall/codex-instruction.js +56 -0
  15. package/dist/cli/postinstall/codex-instruction.js.map +1 -0
  16. package/dist/cli/postinstall/constants.d.ts.map +1 -1
  17. package/dist/cli/postinstall/constants.js +1 -0
  18. package/dist/cli/postinstall/constants.js.map +1 -1
  19. package/dist/cli/postinstall/gemini-agents.d.ts +12 -0
  20. package/dist/cli/postinstall/gemini-agents.d.ts.map +1 -0
  21. package/dist/cli/postinstall/gemini-agents.js +80 -0
  22. package/dist/cli/postinstall/gemini-agents.js.map +1 -0
  23. package/dist/cli/postinstall/gemini-instruction.d.ts +10 -0
  24. package/dist/cli/postinstall/gemini-instruction.d.ts.map +1 -0
  25. package/dist/cli/postinstall/gemini-instruction.js +59 -0
  26. package/dist/cli/postinstall/gemini-instruction.js.map +1 -0
  27. package/dist/cli/postinstall/index.d.ts +4 -0
  28. package/dist/cli/postinstall/index.d.ts.map +1 -1
  29. package/dist/cli/postinstall/index.js +4 -0
  30. package/dist/cli/postinstall/index.js.map +1 -1
  31. package/dist/cli/postinstall/main.d.ts.map +1 -1
  32. package/dist/cli/postinstall/main.js +34 -1
  33. package/dist/cli/postinstall/main.js.map +1 -1
  34. package/dist/cli/postinstall.d.ts +1 -1
  35. package/dist/cli/postinstall.d.ts.map +1 -1
  36. package/dist/cli/postinstall.js +1 -1
  37. package/dist/cli/postinstall.js.map +1 -1
  38. package/dist/cli/setup/ProjectSetup.d.ts +15 -0
  39. package/dist/cli/setup/ProjectSetup.d.ts.map +1 -1
  40. package/dist/cli/setup/ProjectSetup.js +159 -0
  41. package/dist/cli/setup/ProjectSetup.js.map +1 -1
  42. package/dist/cli/setup.d.ts +1 -1
  43. package/dist/cli/setup.d.ts.map +1 -1
  44. package/dist/cli/setup.js +1 -1
  45. package/dist/cli/setup.js.map +1 -1
  46. package/dist/cli/utils/cli-detector.d.ts +25 -0
  47. package/dist/cli/utils/cli-detector.d.ts.map +1 -0
  48. package/dist/cli/utils/cli-detector.js +55 -0
  49. package/dist/cli/utils/cli-detector.js.map +1 -0
  50. package/hooks/gemini-hooks.json +73 -0
  51. package/package.json +1 -1
  52. package/skills/agents-md/SKILL.md +120 -0
  53. package/skills/brand-assets/SKILL.md +8 -0
  54. package/skills/characterization-test/SKILL.md +4 -0
  55. package/skills/commerce-patterns/SKILL.md +36 -338
  56. package/skills/commit-push-pr/SKILL.md +21 -64
  57. package/skills/core-capabilities/SKILL.md +26 -142
  58. package/skills/e2e-commerce/SKILL.md +37 -284
  59. package/skills/frontend-design/SKILL.md +12 -31
  60. package/skills/git-worktree/SKILL.md +34 -146
  61. package/skills/handoff/SKILL.md +8 -0
  62. package/skills/parallel-research/SKILL.md +7 -0
  63. package/skills/priority-todos/SKILL.md +34 -213
  64. package/skills/seo-checklist/SKILL.md +38 -225
  65. package/skills/tool-fallback/SKILL.md +53 -143
  66. package/skills/typescript-advanced-types/SKILL.md +30 -685
  67. package/skills/ui-ux-pro-max/SKILL.md +40 -220
  68. package/skills/vercel-react-best-practices/SKILL.md +38 -283
  69. package/skills/video-production/SKILL.md +35 -206
@@ -19,702 +19,47 @@ sections:
19
19
 
20
20
  # TypeScript Advanced Types
21
21
 
22
- Comprehensive guide for building type-safe applications using TypeScript's advanced type system. Covers Generics, Conditional Types, Mapped Types, Template Literal Types, and Utility Types.
22
+ ## Pre-check (K1)
23
23
 
24
- ## When to Apply
24
+ > Is this a VIBE-specific type safety issue? Standard TypeScript generics/conditionals/mapped types are well-known — read the code instead. This skill exists for VIBE's strict rules and non-obvious gotchas only.
25
25
 
26
- - Building type-safe libraries/frameworks
27
- - Creating reusable generic components
28
- - Implementing complex type inference logic
29
- - Designing type-safe API clients
30
- - Building form validation systems
31
- - Creating strongly-typed configuration objects
32
- - Implementing type-safe state management
33
- - Migrating JavaScript to TypeScript
26
+ ## VIBE Forbidden Patterns
34
27
 
35
- ## VIBE TypeScript Rule Integration
28
+ | Forbidden | Why | Use Instead |
29
+ |-----------|-----|-------------|
30
+ | `any` | Disables all type checking | `unknown` + type guard |
31
+ | `as any` | Bypasses type system | Define proper interface |
32
+ | `@ts-ignore` | Hides real errors | Fix the type issue at root |
33
+ | Raw generic `T` without constraint | Too permissive | `T extends SomeInterface` |
36
34
 
37
- > VIBE blocks `any` type usage. The patterns in this skill provide alternatives for type safety without `any`.
38
-
39
- | Forbidden Pattern | Alternative (from this skill) |
40
- |-------------------|-------------------------------|
41
- | `any` | `unknown` + type guards |
42
- | `as any` | Define proper interfaces |
43
- | `@ts-ignore` | Fix type issues directly |
44
- | Raw generic types | Specify type parameters |
45
-
46
- ## Core Concepts
47
-
48
- ### 1. Generics
49
-
50
- The key tool for creating reusable yet type-safe components.
51
-
52
- **Basic Generic Function:**
53
-
54
- ```typescript
55
- function identity<T>(value: T): T {
56
- return value;
57
- }
58
-
59
- const num = identity<number>(42); // Type: number
60
- const str = identity<string>("hello"); // Type: string
61
- const auto = identity(true); // Type: boolean (inferred)
62
- ```
63
-
64
- **Generic Constraints:**
65
-
66
- ```typescript
67
- interface HasLength {
68
- length: number;
69
- }
70
-
71
- function logLength<T extends HasLength>(item: T): T {
72
- console.log(item.length);
73
- return item;
74
- }
75
-
76
- logLength("hello"); // OK: string has length
77
- logLength([1, 2, 3]); // OK: array has length
78
- // logLength(42); // Error: number has no length
79
- ```
80
-
81
- **Multiple Type Parameters:**
82
-
83
- ```typescript
84
- function merge<T, U>(obj1: T, obj2: U): T & U {
85
- return { ...obj1, ...obj2 };
86
- }
87
-
88
- const merged = merge({ name: "John" }, { age: 30 });
89
- // Type: { name: string } & { age: number }
90
- ```
91
-
92
- ### 2. Conditional Types
93
-
94
- Sophisticated type logic where types are determined by conditions.
95
-
96
- **Basic Conditional Type:**
97
-
98
- ```typescript
99
- type IsString<T> = T extends string ? true : false;
100
-
101
- type A = IsString<string>; // true
102
- type B = IsString<number>; // false
103
- ```
104
-
105
- **Return Type Extraction:**
106
-
107
- ```typescript
108
- type ReturnType<T> = T extends (...args: unknown[]) => infer R ? R : never;
109
-
110
- function getUser() {
111
- return { id: 1, name: "John" };
112
- }
113
-
114
- type User = ReturnType<typeof getUser>;
115
- // Type: { id: number; name: string; }
116
- ```
117
-
118
- **Distributive Conditional Types:**
119
-
120
- ```typescript
121
- type ToArray<T> = T extends unknown ? T[] : never;
122
-
123
- type StrOrNumArray = ToArray<string | number>;
124
- // Type: string[] | number[]
125
- ```
126
-
127
- **Nested Conditions:**
128
-
129
- ```typescript
130
- type TypeName<T> = T extends string
131
- ? "string"
132
- : T extends number
133
- ? "number"
134
- : T extends boolean
135
- ? "boolean"
136
- : T extends undefined
137
- ? "undefined"
138
- : T extends Function
139
- ? "function"
140
- : "object";
141
-
142
- type T1 = TypeName<string>; // "string"
143
- type T2 = TypeName<() => void>; // "function"
144
- ```
145
-
146
- ### 3. Mapped Types
147
-
148
- Types that iterate over and transform properties of existing types.
149
-
150
- **Basic Mapped Type:**
151
-
152
- ```typescript
153
- type Readonly<T> = {
154
- readonly [P in keyof T]: T[P];
155
- };
156
-
157
- interface User {
158
- id: number;
159
- name: string;
160
- }
161
-
162
- type ReadonlyUser = Readonly<User>;
163
- // Type: { readonly id: number; readonly name: string; }
164
- ```
165
-
166
- **Key Remapping:**
167
-
168
- ```typescript
169
- type Getters<T> = {
170
- [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
171
- };
172
-
173
- interface Person {
174
- name: string;
175
- age: number;
176
- }
177
-
178
- type PersonGetters = Getters<Person>;
179
- // Type: { getName: () => string; getAge: () => number; }
180
- ```
181
-
182
- **Property Filtering by Type:**
183
-
184
- ```typescript
185
- type PickByType<T, U> = {
186
- [K in keyof T as T[K] extends U ? K : never]: T[K];
187
- };
188
-
189
- interface Mixed {
190
- id: number;
191
- name: string;
192
- age: number;
193
- active: boolean;
194
- }
195
-
196
- type OnlyNumbers = PickByType<Mixed, number>;
197
- // Type: { id: number; age: number; }
198
- ```
199
-
200
- ### 4. Template Literal Types
201
-
202
- String-based pattern matching and transformation types.
203
-
204
- **Basic Template Literal:**
205
-
206
- ```typescript
207
- type EventName = "click" | "focus" | "blur";
208
- type EventHandler = `on${Capitalize<EventName>}`;
209
- // Type: "onClick" | "onFocus" | "onBlur"
210
- ```
211
-
212
- **String Manipulation:**
213
-
214
- ```typescript
215
- type Upper = Uppercase<"hello">; // "HELLO"
216
- type Lower = Lowercase<"HELLO">; // "hello"
217
- type Cap = Capitalize<"john">; // "John"
218
- type Uncap = Uncapitalize<"John">; // "john"
219
- ```
220
-
221
- **Path Builder:**
222
-
223
- ```typescript
224
- type Path<T> = T extends object
225
- ? {
226
- [K in keyof T]: K extends string
227
- ? `${K}` | `${K}.${Path<T[K]>}`
228
- : never;
229
- }[keyof T]
230
- : never;
231
-
232
- interface Config {
233
- server: { host: string; port: number };
234
- database: { url: string };
235
- }
236
-
237
- type ConfigPath = Path<Config>;
238
- // Type: "server" | "database" | "server.host" | "server.port" | "database.url"
239
- ```
240
-
241
- ### 5. Utility Types
242
-
243
- Built-in TypeScript utility types.
244
-
245
- ```typescript
246
- // Partial<T> — make all properties optional
247
- type PartialUser = Partial<User>;
248
-
249
- // Required<T> — make all properties required
250
- type RequiredUser = Required<PartialUser>;
251
-
252
- // Readonly<T> — make all properties readonly
253
- type ReadonlyUser = Readonly<User>;
254
-
255
- // Pick<T, K> — pick specific properties
256
- type UserName = Pick<User, "name" | "email">;
257
-
258
- // Omit<T, K> — omit specific properties
259
- type UserWithoutPassword = Omit<User, "password">;
260
-
261
- // Exclude<T, U> — exclude types from union
262
- type T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
263
-
264
- // Extract<T, U> — extract types from union
265
- type T2 = Extract<"a" | "b" | "c", "a" | "b">; // "a" | "b"
266
-
267
- // NonNullable<T> — exclude null/undefined
268
- type T3 = NonNullable<string | null | undefined>; // string
269
-
270
- // Record<K, T> — object type with keys K and values T
271
- type PageInfo = Record<"home" | "about", { title: string }>;
272
- ```
273
-
274
- ## Advanced Patterns
275
-
276
- ### Pattern 1: Type-safe Event Emitter
277
-
278
- ```typescript
279
- type EventMap = {
280
- "user:created": { id: string; name: string };
281
- "user:updated": { id: string };
282
- "user:deleted": { id: string };
283
- };
284
-
285
- class TypedEventEmitter<T extends Record<string, unknown>> {
286
- private listeners: {
287
- [K in keyof T]?: Array<(data: T[K]) => void>;
288
- } = {};
289
-
290
- on<K extends keyof T>(event: K, callback: (data: T[K]) => void): void {
291
- if (!this.listeners[event]) {
292
- this.listeners[event] = [];
293
- }
294
- this.listeners[event]!.push(callback);
295
- }
296
-
297
- emit<K extends keyof T>(event: K, data: T[K]): void {
298
- const callbacks = this.listeners[event];
299
- if (callbacks) {
300
- callbacks.forEach((cb) => cb(data));
301
- }
302
- }
303
- }
304
-
305
- const emitter = new TypedEventEmitter<EventMap>();
306
- emitter.on("user:created", (data) => {
307
- console.log(data.id, data.name); // type-safe!
308
- });
309
- ```
310
-
311
- ### Pattern 2: Type-safe API Client
312
-
313
- ```typescript
314
- type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
315
-
316
- type EndpointConfig = {
317
- "/users": {
318
- GET: { response: User[] };
319
- POST: { body: { name: string; email: string }; response: User };
320
- };
321
- "/users/:id": {
322
- GET: { params: { id: string }; response: User };
323
- PUT: { params: { id: string }; body: Partial<User>; response: User };
324
- DELETE: { params: { id: string }; response: void };
325
- };
326
- };
327
-
328
- type ExtractParams<T> = T extends { params: infer P } ? P : never;
329
- type ExtractBody<T> = T extends { body: infer B } ? B : never;
330
- type ExtractResponse<T> = T extends { response: infer R } ? R : never;
331
-
332
- class APIClient<Config extends Record<string, Record<string, unknown>>> {
333
- async request<
334
- Path extends keyof Config,
335
- Method extends keyof Config[Path]
336
- >(
337
- path: Path,
338
- method: Method,
339
- ...[options]: ExtractParams<Config[Path][Method]> extends never
340
- ? ExtractBody<Config[Path][Method]> extends never
341
- ? []
342
- : [{ body: ExtractBody<Config[Path][Method]> }]
343
- : [
344
- {
345
- params: ExtractParams<Config[Path][Method]>;
346
- body?: ExtractBody<Config[Path][Method]>;
347
- },
348
- ]
349
- ): Promise<ExtractResponse<Config[Path][Method]>> {
350
- // implementation
351
- return {} as ExtractResponse<Config[Path][Method]>;
352
- }
353
- }
354
-
355
- const api = new APIClient<EndpointConfig>();
356
-
357
- // Type-safe API calls
358
- const users = await api.request("/users", "GET");
359
- // Type: User[]
360
-
361
- const newUser = await api.request("/users", "POST", {
362
- body: { name: "John", email: "john@example.com" },
363
- });
364
- // Type: User
365
-
366
- const user = await api.request("/users/:id", "GET", {
367
- params: { id: "123" },
368
- });
369
- // Type: User
370
- ```
371
-
372
- ### Pattern 3: Deep Readonly/Partial
373
-
374
- ```typescript
375
- type DeepReadonly<T> = {
376
- readonly [P in keyof T]: T[P] extends object
377
- ? T[P] extends Function
378
- ? T[P]
379
- : DeepReadonly<T[P]>
380
- : T[P];
381
- };
382
-
383
- type DeepPartial<T> = {
384
- [P in keyof T]?: T[P] extends object
385
- ? T[P] extends Array<infer U>
386
- ? Array<DeepPartial<U>>
387
- : DeepPartial<T[P]>
388
- : T[P];
389
- };
390
- ```
391
-
392
- ### Pattern 4: Type-safe Form Validation
393
-
394
- ```typescript
395
- type ValidationRule<T> = {
396
- validate: (value: T) => boolean;
397
- message: string;
398
- };
399
-
400
- type FieldValidation<T> = {
401
- [K in keyof T]?: ValidationRule<T[K]>[];
402
- };
403
-
404
- type ValidationErrors<T> = {
405
- [K in keyof T]?: string[];
406
- };
407
-
408
- class FormValidator<T extends Record<string, unknown>> {
409
- constructor(private rules: FieldValidation<T>) {}
410
-
411
- validate(data: T): ValidationErrors<T> | null {
412
- const errors: ValidationErrors<T> = {};
413
- let hasErrors = false;
414
-
415
- for (const key in this.rules) {
416
- const fieldRules = this.rules[key];
417
- const value = data[key];
418
-
419
- if (fieldRules) {
420
- const fieldErrors: string[] = [];
421
- for (const rule of fieldRules) {
422
- if (!rule.validate(value)) {
423
- fieldErrors.push(rule.message);
424
- }
425
- }
426
- if (fieldErrors.length > 0) {
427
- errors[key] = fieldErrors;
428
- hasErrors = true;
429
- }
430
- }
431
- }
432
-
433
- return hasErrors ? errors : null;
434
- }
435
- }
436
- ```
437
-
438
- ### Pattern 5: Discriminated Unions
439
-
440
- ```typescript
441
- type Success<T> = { status: "success"; data: T };
442
- type Failure = { status: "error"; error: string };
443
- type Pending = { status: "loading" };
444
-
445
- type AsyncState<T> = Success<T> | Failure | Pending;
446
-
447
- function handleState<T>(state: AsyncState<T>): void {
448
- switch (state.status) {
449
- case "success":
450
- console.log(state.data); // Type: T
451
- break;
452
- case "error":
453
- console.log(state.error); // Type: string
454
- break;
455
- case "loading":
456
- console.log("Loading...");
457
- break;
458
- }
459
- }
460
- ```
461
-
462
- **Type-safe State Machine:**
463
-
464
- ```typescript
465
- type State =
466
- | { type: "idle" }
467
- | { type: "fetching"; requestId: string }
468
- | { type: "success"; data: unknown }
469
- | { type: "error"; error: Error };
470
-
471
- type Event =
472
- | { type: "FETCH"; requestId: string }
473
- | { type: "SUCCESS"; data: unknown }
474
- | { type: "ERROR"; error: Error }
475
- | { type: "RESET" };
476
-
477
- function reducer(state: State, event: Event): State {
478
- switch (state.type) {
479
- case "idle":
480
- return event.type === "FETCH"
481
- ? { type: "fetching", requestId: event.requestId }
482
- : state;
483
- case "fetching":
484
- if (event.type === "SUCCESS") {
485
- return { type: "success", data: event.data };
486
- }
487
- if (event.type === "ERROR") {
488
- return { type: "error", error: event.error };
489
- }
490
- return state;
491
- case "success":
492
- case "error":
493
- return event.type === "RESET" ? { type: "idle" } : state;
494
- }
495
- }
496
- ```
497
-
498
- ### Pattern 6: Builder Pattern (Type-safe)
499
-
500
- ```typescript
501
- type BuilderState<T> = {
502
- [K in keyof T]: T[K] | undefined;
503
- };
504
-
505
- type RequiredKeys<T> = {
506
- [K in keyof T]-?: Record<string, never> extends Pick<T, K> ? never : K;
507
- }[keyof T];
508
-
509
- type IsComplete<T, S> =
510
- RequiredKeys<T> extends keyof S
511
- ? S[RequiredKeys<T>] extends undefined
512
- ? false
513
- : true
514
- : false;
515
-
516
- class Builder<T, S extends BuilderState<T> = Record<string, never> & BuilderState<T>> {
517
- private state: S = {} as S;
518
-
519
- set<K extends keyof T>(key: K, value: T[K]): Builder<T, S & Record<K, T[K]>> {
520
- (this.state as Record<string, unknown>)[key as string] = value;
521
- return this as unknown as Builder<T, S & Record<K, T[K]>>;
522
- }
523
-
524
- build(this: IsComplete<T, S> extends true ? Builder<T, S> : never): T {
525
- return this.state as unknown as T;
526
- }
527
- }
528
-
529
- interface UserConfig {
530
- id: string;
531
- name: string;
532
- email: string;
533
- age?: number;
534
- }
535
-
536
- const userBuilder = new Builder<UserConfig>();
537
-
538
- const config = userBuilder
539
- .set("id", "1")
540
- .set("name", "John")
541
- .set("email", "john@example.com")
542
- .build(); // OK: all required fields set
543
-
544
- // const incomplete = userBuilder
545
- // .set("id", "1")
546
- // .build(); // Error: required fields missing
547
- ```
548
-
549
- ### Pattern 7: Deep Readonly/Partial Usage
35
+ ## `unknown` + Type Guard (VIBE's `any` Replacement)
550
36
 
551
37
  ```typescript
552
- interface AppConfig {
553
- server: {
554
- host: string;
555
- port: number;
556
- ssl: {
557
- enabled: boolean;
558
- cert: string;
559
- };
560
- };
561
- database: {
562
- url: string;
563
- pool: {
564
- min: number;
565
- max: number;
566
- };
567
- };
38
+ // Instead of: function process(data: any)
39
+ function process(data: unknown): string {
40
+ if (typeof data === 'string') return data.toUpperCase();
41
+ if (isUser(data)) return data.name;
42
+ throw new Error('Unexpected data type');
568
43
  }
569
44
 
570
- type ReadonlyConfig = DeepReadonly<AppConfig>;
571
- // All nested properties are readonly
572
-
573
- type PartialConfig = DeepPartial<AppConfig>;
574
- // All nested properties are optional
575
-
576
- // Used in config update function
577
- function updateConfig(current: AppConfig, patch: DeepPartial<AppConfig>): AppConfig {
578
- return deepMerge(current, patch);
45
+ function isUser(value: unknown): value is User {
46
+ return typeof value === 'object' && value !== null && 'name' in value;
579
47
  }
580
48
  ```
581
49
 
582
- ### Pattern 8: Form Validation Usage
583
-
584
- ```typescript
585
- interface LoginForm {
586
- email: string;
587
- password: string;
588
- }
589
-
590
- const loginValidator = new FormValidator<LoginForm>({
591
- email: [
592
- {
593
- validate: (v) => v.includes("@"),
594
- message: "Invalid email format",
595
- },
596
- {
597
- validate: (v) => v.length > 0,
598
- message: "Email is required",
599
- },
600
- ],
601
- password: [
602
- {
603
- validate: (v) => v.length >= 8,
604
- message: "Password must be at least 8 characters",
605
- },
606
- ],
607
- });
608
-
609
- const errors = loginValidator.validate({
610
- email: "invalid",
611
- password: "short",
612
- });
613
- // Type: { email?: string[]; password?: string[]; } | null
614
- ```
615
-
616
- ## Type Inference Techniques
617
-
618
- ### 1. The Infer Keyword
619
-
620
- ```typescript
621
- // Extract array element type
622
- type ElementType<T> = T extends (infer U)[] ? U : never;
623
- type Num = ElementType<number[]>; // number
624
-
625
- // Extract Promise type
626
- type PromiseType<T> = T extends Promise<infer U> ? U : never;
627
- type AsyncNum = PromiseType<Promise<number>>; // number
628
-
629
- // Extract function parameters
630
- type Parameters<T> = T extends (...args: infer P) => unknown ? P : never;
631
- ```
632
-
633
- ### 2. Type Guards
634
-
635
- ```typescript
636
- function isString(value: unknown): value is string {
637
- return typeof value === "string";
638
- }
639
-
640
- function isArrayOf<T>(
641
- value: unknown,
642
- guard: (item: unknown) => item is T,
643
- ): value is T[] {
644
- return Array.isArray(value) && value.every(guard);
645
- }
646
-
647
- const data: unknown = ["a", "b", "c"];
648
- if (isArrayOf(data, isString)) {
649
- data.forEach((s) => s.toUpperCase()); // Type: string[]
650
- }
651
- ```
652
-
653
- ### 3. Assertion Functions
654
-
655
- ```typescript
656
- function assertIsString(value: unknown): asserts value is string {
657
- if (typeof value !== "string") {
658
- throw new Error("Not a string");
659
- }
660
- }
661
-
662
- function processValue(value: unknown): void {
663
- assertIsString(value);
664
- // value is now typed as string
665
- console.log(value.toUpperCase());
666
- }
667
- ```
668
-
669
- ## Best Practices
670
-
671
- 1. **Use `unknown` instead of `any`**: Forces type validation
672
- 2. **Use `interface` for object shapes**: Better error messages
673
- 3. **Use `type` for unions/complex types**: More flexible
674
- 4. **Leverage type inference**: Omit explicit types when TypeScript can infer
675
- 5. **Create helper types**: Build reusable type utilities
676
- 6. **Use const assertions**: Preserve literal types
677
- 7. **Avoid type assertions**: Use type guards instead
678
- 8. **Document complex types**: Add JSDoc comments
679
- 9. **Use strict mode**: Enable all strict compiler options
680
- 10. **Test your types**: Verify type behavior
681
-
682
- ## Type Testing
683
-
684
- ```typescript
685
- // Type equality assertion test
686
- type AssertEqual<T, U> = [T] extends [U]
687
- ? [U] extends [T]
688
- ? true
689
- : false
690
- : false;
691
-
692
- type Test1 = AssertEqual<string, string>; // true
693
- type Test2 = AssertEqual<string, number>; // false
694
- ```
695
-
696
- ## Common Mistakes
697
-
698
- 1. **Overusing `any`**: Defeats the purpose of TypeScript
699
- 2. **Ignoring strict null checks**: Causes runtime errors
700
- 3. **Overly complex types**: Slows down compilation
701
- 4. **Not using discriminated unions**: Misses type narrowing opportunities
702
- 5. **Missing readonly modifiers**: Allows unintended mutations
703
- 6. **Circular type references**: Causes compiler errors
704
- 7. **Unhandled edge cases**: Empty arrays, null values, etc.
705
-
706
- ## Performance Considerations
707
-
708
- - Avoid deeply nested conditional types
709
- - Use simpler types when possible
710
- - Cache complex type computations
711
- - Limit depth of recursive types
712
- - Use tools that skip type checking in production builds
50
+ ## Gotchas
713
51
 
714
- ## References
52
+ | Gotcha | Why Non-obvious | Fix |
53
+ |--------|----------------|-----|
54
+ | Distributive conditionals | `ToArray<string \| number>` → `string[] \| number[]`, not `(string \| number)[]` | Wrap in tuple: `[T] extends [U]` |
55
+ | Recursive type depth | TS has ~50 level depth limit | Use tail-recursive patterns or simplify |
56
+ | `satisfies` vs `as const` | `satisfies` validates + keeps literal types; `as` skips validation | Prefer `satisfies` |
57
+ | Type assertions (`as X`) | Skips checking entirely | Use type guards instead |
58
+ | `interface` vs `type` | `interface` gives better error messages for objects | Use `type` for unions/complex, `interface` for shapes |
715
59
 
716
- - TypeScript Handbook: https://www.typescriptlang.org/docs/handbook/
717
- - Type Challenges: https://github.com/type-challenges/type-challenges
718
- - Effective TypeScript (by Dan Vanderkam)
60
+ ## Done Criteria (K4)
719
61
 
720
- > **VIBE tool integration**: `core_validate_code_quality` detects `any` type usage, `core_apply_quality_rules` auto-applies TypeScript rules
62
+ - [ ] No `any`, `as any`, or `@ts-ignore` in code
63
+ - [ ] All `unknown` usages have corresponding type guards
64
+ - [ ] Complex types have `AssertEqual` type tests
65
+ - [ ] Recursive types are bounded (no infinite depth)