@biggora/claude-plugins 1.2.2 → 1.3.1
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/README.md +5 -1
- package/package.json +1 -1
- package/registry/registry.json +15 -0
- package/specs/coding.md +11 -0
- package/src/commands/skills/add.js +115 -31
- package/src/commands/skills/list.js +25 -52
- package/src/commands/skills/remove.js +45 -27
- package/src/commands/skills/resolve.js +104 -0
- package/src/commands/skills/update.js +58 -74
- package/src/config.js +5 -0
- package/src/skills/nest-best-practices/SKILL.md +251 -0
- package/src/skills/nest-best-practices/references/best-practices-request-lifecycle.md +158 -0
- package/src/skills/nest-best-practices/references/cli-monorepo.md +106 -0
- package/src/skills/nest-best-practices/references/cli-overview.md +157 -0
- package/src/skills/nest-best-practices/references/core-controllers.md +165 -0
- package/src/skills/nest-best-practices/references/core-dependency-injection.md +179 -0
- package/src/skills/nest-best-practices/references/core-middleware.md +139 -0
- package/src/skills/nest-best-practices/references/core-modules.md +138 -0
- package/src/skills/nest-best-practices/references/core-providers.md +188 -0
- package/src/skills/nest-best-practices/references/faq-raw-body-hybrid.md +122 -0
- package/src/skills/nest-best-practices/references/fundamentals-circular-dependency.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-custom-decorators.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-dynamic-modules.md +125 -0
- package/src/skills/nest-best-practices/references/fundamentals-exception-filters.md +202 -0
- package/src/skills/nest-best-practices/references/fundamentals-execution-context.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-guards.md +136 -0
- package/src/skills/nest-best-practices/references/fundamentals-interceptors.md +187 -0
- package/src/skills/nest-best-practices/references/fundamentals-lazy-loading.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-lifecycle-events.md +87 -0
- package/src/skills/nest-best-practices/references/fundamentals-module-reference.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-pipes.md +197 -0
- package/src/skills/nest-best-practices/references/fundamentals-provider-scopes.md +92 -0
- package/src/skills/nest-best-practices/references/fundamentals-testing.md +142 -0
- package/src/skills/nest-best-practices/references/graphql-overview.md +233 -0
- package/src/skills/nest-best-practices/references/graphql-resolvers-mutations.md +199 -0
- package/src/skills/nest-best-practices/references/graphql-scalars-unions-enums.md +180 -0
- package/src/skills/nest-best-practices/references/graphql-subscriptions.md +228 -0
- package/src/skills/nest-best-practices/references/microservices-grpc.md +175 -0
- package/src/skills/nest-best-practices/references/microservices-overview.md +221 -0
- package/src/skills/nest-best-practices/references/microservices-transports.md +119 -0
- package/src/skills/nest-best-practices/references/openapi-swagger.md +207 -0
- package/src/skills/nest-best-practices/references/recipes-authentication.md +97 -0
- package/src/skills/nest-best-practices/references/recipes-cqrs.md +176 -0
- package/src/skills/nest-best-practices/references/recipes-crud-generator.md +87 -0
- package/src/skills/nest-best-practices/references/recipes-documentation.md +93 -0
- package/src/skills/nest-best-practices/references/recipes-mongoose.md +153 -0
- package/src/skills/nest-best-practices/references/recipes-prisma.md +98 -0
- package/src/skills/nest-best-practices/references/recipes-terminus.md +148 -0
- package/src/skills/nest-best-practices/references/recipes-typeorm.md +122 -0
- package/src/skills/nest-best-practices/references/security-authorization.md +196 -0
- package/src/skills/nest-best-practices/references/security-cors-helmet-rate-limiting.md +204 -0
- package/src/skills/nest-best-practices/references/security-encryption-hashing.md +93 -0
- package/src/skills/nest-best-practices/references/techniques-caching.md +142 -0
- package/src/skills/nest-best-practices/references/techniques-compression-streaming-sse.md +194 -0
- package/src/skills/nest-best-practices/references/techniques-configuration.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-database.md +153 -0
- package/src/skills/nest-best-practices/references/techniques-events.md +163 -0
- package/src/skills/nest-best-practices/references/techniques-fastify.md +137 -0
- package/src/skills/nest-best-practices/references/techniques-file-upload.md +140 -0
- package/src/skills/nest-best-practices/references/techniques-http-module.md +176 -0
- package/src/skills/nest-best-practices/references/techniques-logging.md +146 -0
- package/src/skills/nest-best-practices/references/techniques-mvc-serve-static.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-queues.md +162 -0
- package/src/skills/nest-best-practices/references/techniques-serialization.md +158 -0
- package/src/skills/nest-best-practices/references/techniques-sessions-cookies.md +167 -0
- package/src/skills/nest-best-practices/references/techniques-task-scheduling.md +166 -0
- package/src/skills/nest-best-practices/references/techniques-validation.md +126 -0
- package/src/skills/nest-best-practices/references/techniques-versioning.md +153 -0
- package/src/skills/nest-best-practices/references/websockets-advanced.md +96 -0
- package/src/skills/nest-best-practices/references/websockets-gateways.md +215 -0
- package/src/skills/typescript-expert/SKILL.md +145 -0
- package/src/skills/typescript-expert/commands/typescript-fix.md +65 -0
- package/src/skills/typescript-expert/references/advanced-conditional-types.md +190 -0
- package/src/skills/typescript-expert/references/advanced-decorators.md +243 -0
- package/src/skills/typescript-expert/references/advanced-mapped-types.md +223 -0
- package/src/skills/typescript-expert/references/advanced-template-literals.md +209 -0
- package/src/skills/typescript-expert/references/advanced-type-guards.md +308 -0
- package/src/skills/typescript-expert/references/best-practices-patterns.md +313 -0
- package/src/skills/typescript-expert/references/best-practices-performance.md +185 -0
- package/src/skills/typescript-expert/references/best-practices-tsconfig.md +242 -0
- package/src/skills/typescript-expert/references/core-generics.md +246 -0
- package/src/skills/typescript-expert/references/core-interfaces-types.md +231 -0
- package/src/skills/typescript-expert/references/core-type-system.md +261 -0
- package/src/skills/typescript-expert/references/core-utility-types.md +235 -0
- package/src/skills/typescript-expert/references/features-ts5x.md +370 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: websockets
|
|
3
|
+
description: Real-time communication with WebSocket gateways
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# WebSockets
|
|
7
|
+
|
|
8
|
+
NestJS provides WebSocket support through gateways, with built-in adapters for Socket.IO and ws.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @nestjs/websockets @nestjs/platform-socket.io
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Basic Gateway
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import {
|
|
20
|
+
WebSocketGateway,
|
|
21
|
+
WebSocketServer,
|
|
22
|
+
SubscribeMessage,
|
|
23
|
+
MessageBody,
|
|
24
|
+
ConnectedSocket,
|
|
25
|
+
} from '@nestjs/websockets';
|
|
26
|
+
import { Server, Socket } from 'socket.io';
|
|
27
|
+
|
|
28
|
+
@WebSocketGateway()
|
|
29
|
+
export class EventsGateway {
|
|
30
|
+
@WebSocketServer()
|
|
31
|
+
server: Server;
|
|
32
|
+
|
|
33
|
+
@SubscribeMessage('events')
|
|
34
|
+
handleEvent(@MessageBody() data: string): string {
|
|
35
|
+
return data; // Sends acknowledgment
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Gateway Configuration
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
@WebSocketGateway(81, {
|
|
44
|
+
namespace: 'events',
|
|
45
|
+
cors: { origin: '*' },
|
|
46
|
+
transports: ['websocket'],
|
|
47
|
+
})
|
|
48
|
+
export class EventsGateway {}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Message Handlers
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
@SubscribeMessage('message')
|
|
55
|
+
handleMessage(
|
|
56
|
+
@MessageBody() data: { text: string },
|
|
57
|
+
@ConnectedSocket() client: Socket,
|
|
58
|
+
): WsResponse<string> {
|
|
59
|
+
// Return emits event back to client
|
|
60
|
+
return { event: 'response', data: data.text };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Extract specific property
|
|
64
|
+
@SubscribeMessage('message')
|
|
65
|
+
handleMessage(@MessageBody('id') id: number): number {
|
|
66
|
+
return id;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Async Responses
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
@SubscribeMessage('events')
|
|
74
|
+
async handleEvent(@MessageBody() data: any): Promise<WsResponse<any>> {
|
|
75
|
+
const result = await this.service.process(data);
|
|
76
|
+
return { event: 'processed', data: result };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Observable (emits multiple responses)
|
|
80
|
+
@SubscribeMessage('events')
|
|
81
|
+
handleEvent(): Observable<WsResponse<number>> {
|
|
82
|
+
return from([1, 2, 3]).pipe(
|
|
83
|
+
map((item) => ({ event: 'events', data: item })),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Acknowledgment Callback
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
@SubscribeMessage('events')
|
|
92
|
+
handleEvent(
|
|
93
|
+
@MessageBody() data: string,
|
|
94
|
+
@Ack() ack: (response: any) => void,
|
|
95
|
+
) {
|
|
96
|
+
ack({ status: 'received', data });
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Lifecycle Hooks
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import {
|
|
104
|
+
OnGatewayInit,
|
|
105
|
+
OnGatewayConnection,
|
|
106
|
+
OnGatewayDisconnect,
|
|
107
|
+
} from '@nestjs/websockets';
|
|
108
|
+
|
|
109
|
+
@WebSocketGateway()
|
|
110
|
+
export class EventsGateway
|
|
111
|
+
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
|
|
112
|
+
{
|
|
113
|
+
@WebSocketServer()
|
|
114
|
+
server: Server;
|
|
115
|
+
|
|
116
|
+
afterInit(server: Server) {
|
|
117
|
+
console.log('Gateway initialized');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
handleConnection(client: Socket) {
|
|
121
|
+
console.log(`Client connected: ${client.id}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
handleDisconnect(client: Socket) {
|
|
125
|
+
console.log(`Client disconnected: ${client.id}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Broadcasting
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
@SubscribeMessage('broadcast')
|
|
134
|
+
handleBroadcast(@MessageBody() data: any) {
|
|
135
|
+
// Emit to all connected clients
|
|
136
|
+
this.server.emit('broadcast', data);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Emit to specific room
|
|
140
|
+
emitToRoom(room: string, event: string, data: any) {
|
|
141
|
+
this.server.to(room).emit(event, data);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Join/leave rooms
|
|
145
|
+
@SubscribeMessage('joinRoom')
|
|
146
|
+
handleJoinRoom(
|
|
147
|
+
@ConnectedSocket() client: Socket,
|
|
148
|
+
@MessageBody() room: string,
|
|
149
|
+
) {
|
|
150
|
+
client.join(room);
|
|
151
|
+
return { event: 'joinedRoom', data: room };
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Namespace Access
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
@WebSocketGateway({ namespace: 'chat' })
|
|
159
|
+
export class ChatGateway {
|
|
160
|
+
@WebSocketServer()
|
|
161
|
+
namespace: Namespace;
|
|
162
|
+
|
|
163
|
+
getConnectedClients() {
|
|
164
|
+
return this.namespace.sockets.size;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Using Guards and Pipes
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
@UseGuards(WsAuthGuard)
|
|
173
|
+
@UsePipes(new ValidationPipe())
|
|
174
|
+
@SubscribeMessage('message')
|
|
175
|
+
handleMessage(@MessageBody() dto: CreateMessageDto) {
|
|
176
|
+
return this.messagesService.create(dto);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Register in Module
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
@Module({
|
|
184
|
+
providers: [EventsGateway],
|
|
185
|
+
})
|
|
186
|
+
export class EventsModule {}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Client Example
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// Client-side
|
|
193
|
+
const socket = io('http://localhost:3000');
|
|
194
|
+
|
|
195
|
+
socket.emit('events', { name: 'Nest' }, (response) => {
|
|
196
|
+
console.log('Acknowledgment:', response);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
socket.on('events', (data) => {
|
|
200
|
+
console.log('Received:', data);
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Key Points
|
|
205
|
+
|
|
206
|
+
- Gateways are registered as providers
|
|
207
|
+
- Default port is same as HTTP server
|
|
208
|
+
- Guards, pipes, and interceptors work with gateways
|
|
209
|
+
- Use `@ConnectedSocket()` to access the socket instance
|
|
210
|
+
- Return value from handler sends acknowledgment
|
|
211
|
+
|
|
212
|
+
<!--
|
|
213
|
+
Source references:
|
|
214
|
+
- https://docs.nestjs.com/websockets/gateways
|
|
215
|
+
-->
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: typescript-expert
|
|
3
|
+
description: TypeScript language expertise covering the type system, generics, utility types, advanced type patterns, and project configuration. Use this skill whenever writing, reviewing, or refactoring TypeScript code, designing type-safe APIs, working with complex generics, debugging type errors, configuring tsconfig.json, migrating JavaScript to TypeScript, or leveraging TypeScript 5.x features like satisfies, const type parameters, decorators, and the using keyword. Also use when the user asks about type narrowing, conditional types, mapped types, template literal types, branded types, discriminated unions, or any TypeScript type system question — even seemingly simple ones, because TypeScript's type system has subtle gotchas that catch experienced developers.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TypeScript Expert
|
|
7
|
+
|
|
8
|
+
> Covers TypeScript through 5.8 (latest stable as of March 2026). The official handbook at https://www.typescriptlang.org/docs/handbook/ is the canonical reference.
|
|
9
|
+
|
|
10
|
+
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Its type system is structural (not nominal), meaning type compatibility is determined by shape rather than declaration. This has profound implications for how you design types and APIs.
|
|
11
|
+
|
|
12
|
+
## Quick Decision Guide
|
|
13
|
+
|
|
14
|
+
| You need to... | Read |
|
|
15
|
+
|----------------|------|
|
|
16
|
+
| Understand primitives, inference, narrowing | [core-type-system](references/core-type-system.md) |
|
|
17
|
+
| Choose between `interface` and `type` | [core-interfaces-types](references/core-interfaces-types.md) |
|
|
18
|
+
| Write generic functions, classes, constraints | [core-generics](references/core-generics.md) |
|
|
19
|
+
| Use `Partial`, `Pick`, `Omit`, `Record`, etc. | [core-utility-types](references/core-utility-types.md) |
|
|
20
|
+
| Build conditional types with `infer` | [advanced-conditional-types](references/advanced-conditional-types.md) |
|
|
21
|
+
| Create mapped types and key remapping | [advanced-mapped-types](references/advanced-mapped-types.md) |
|
|
22
|
+
| Use template literal types for string patterns | [advanced-template-literals](references/advanced-template-literals.md) |
|
|
23
|
+
| Narrow types with guards and discriminated unions | [advanced-type-guards](references/advanced-type-guards.md) |
|
|
24
|
+
| Use TC39 decorators (TS 5.0+) | [advanced-decorators](references/advanced-decorators.md) |
|
|
25
|
+
| Configure `tsconfig.json` properly | [best-practices-tsconfig](references/best-practices-tsconfig.md) |
|
|
26
|
+
| Apply common patterns (branded types, error handling, immutability) | [best-practices-patterns](references/best-practices-patterns.md) |
|
|
27
|
+
| Optimize type-level performance | [best-practices-performance](references/best-practices-performance.md) |
|
|
28
|
+
| Use TS 5.0-5.8 features (`satisfies`, `const` params, `using`) | [features-ts5x](references/features-ts5x.md) |
|
|
29
|
+
|
|
30
|
+
## Core Principles
|
|
31
|
+
|
|
32
|
+
### 1. Let TypeScript Infer
|
|
33
|
+
|
|
34
|
+
TypeScript's inference is powerful. Don't annotate what TypeScript can figure out on its own:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// Unnecessary — TypeScript infers `number`
|
|
38
|
+
const count: number = 5;
|
|
39
|
+
|
|
40
|
+
// Good — let inference work
|
|
41
|
+
const count = 5;
|
|
42
|
+
|
|
43
|
+
// DO annotate function signatures (parameters + return types for public APIs)
|
|
44
|
+
function getUser(id: string): Promise<User> { ... }
|
|
45
|
+
|
|
46
|
+
// Return type annotation catches accidental returns
|
|
47
|
+
function parse(input: string): ParseResult {
|
|
48
|
+
if (!input) return null; // Error! null isn't ParseResult — good, we caught a bug
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Prefer `unknown` over `any`
|
|
53
|
+
|
|
54
|
+
`any` disables type checking. `unknown` is type-safe — you must narrow it before use:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// Bad — silently breaks type safety
|
|
58
|
+
function process(data: any) {
|
|
59
|
+
data.foo.bar; // No error, but might crash at runtime
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Good — forces you to check before using
|
|
63
|
+
function process(data: unknown) {
|
|
64
|
+
if (typeof data === "object" && data !== null && "foo" in data) {
|
|
65
|
+
// Now TypeScript knows data has a foo property
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 3. Use Strict Mode
|
|
71
|
+
|
|
72
|
+
Always enable `"strict": true` in tsconfig.json. It enables all strict type-checking flags including `strictNullChecks`, `noImplicitAny`, and `strictFunctionTypes`. Projects that skip strict mode accumulate hidden bugs that surface painfully later. See [best-practices-tsconfig](references/best-practices-tsconfig.md) for the full recommended configuration.
|
|
73
|
+
|
|
74
|
+
### 4. Model Your Domain with Types
|
|
75
|
+
|
|
76
|
+
The type system is a tool for encoding business rules. Use discriminated unions to model states, branded types for domain identifiers, and `readonly` to enforce immutability:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// Model states explicitly — impossible to access data in loading/error state
|
|
80
|
+
type AsyncState<T> =
|
|
81
|
+
| { status: "loading" }
|
|
82
|
+
| { status: "error"; error: Error }
|
|
83
|
+
| { status: "success"; data: T };
|
|
84
|
+
|
|
85
|
+
// Branded types prevent ID mixups at compile time
|
|
86
|
+
type UserId = string & { readonly __brand: "UserId" };
|
|
87
|
+
type OrderId = string & { readonly __brand: "OrderId" };
|
|
88
|
+
|
|
89
|
+
function getOrder(orderId: OrderId): Order { ... }
|
|
90
|
+
getOrder(userId); // Error! UserId is not assignable to OrderId
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 5. Structural Typing Implications
|
|
94
|
+
|
|
95
|
+
TypeScript uses structural typing — if two types have the same shape, they're compatible:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
interface Point { x: number; y: number }
|
|
99
|
+
interface Coordinate { x: number; y: number }
|
|
100
|
+
|
|
101
|
+
const p: Point = { x: 1, y: 2 };
|
|
102
|
+
const c: Coordinate = p; // OK — same shape
|
|
103
|
+
|
|
104
|
+
// This means excess property checks only apply to object literals
|
|
105
|
+
function plot(point: Point) { ... }
|
|
106
|
+
plot({ x: 1, y: 2, z: 3 }); // Error — excess property check on literal
|
|
107
|
+
const obj = { x: 1, y: 2, z: 3 };
|
|
108
|
+
plot(obj); // OK — no excess check on variable
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Common Gotchas
|
|
112
|
+
|
|
113
|
+
| Gotcha | Explanation |
|
|
114
|
+
|--------|-------------|
|
|
115
|
+
| `object` vs `Object` vs `{}` | Use `object` for non-primitives. Never use `Object` or `{}` as types — `{}` matches everything except `null`/`undefined`. |
|
|
116
|
+
| `T[]` vs `readonly T[]` | Arrays are mutable by default. Use `readonly T[]` or `ReadonlyArray<T>` when mutation isn't intended. |
|
|
117
|
+
| `enum` vs union | Prefer union types (`type Dir = "N" \| "S" \| "E" \| "W"`) over enums. Enums produce runtime code and have subtle nominal typing behavior. Use `as const` objects if you need runtime values. |
|
|
118
|
+
| Optional vs `undefined` | `{ x?: number }` means x may be missing entirely. `{ x: number \| undefined }` means x must be present but can be undefined. These behave differently with `in` checks and spread. |
|
|
119
|
+
| `as` casts | Type assertions (`as`) override the compiler. Prefer type guards for runtime narrowing. Use `as` only when you genuinely know more than TypeScript. |
|
|
120
|
+
| `any` propagation | A single `any` silently infects surrounding types. Use `unknown` and narrow, or use `// @ts-expect-error` for known edge cases. |
|
|
121
|
+
|
|
122
|
+
## TypeScript 5.x Highlights
|
|
123
|
+
|
|
124
|
+
Key features added in TypeScript 5.0-5.8 (see [features-ts5x](references/features-ts5x.md) for details):
|
|
125
|
+
|
|
126
|
+
| Version | Feature | Why it matters |
|
|
127
|
+
|---------|---------|----------------|
|
|
128
|
+
| 5.0 | TC39 Decorators | Standard decorator syntax, no `experimentalDecorators` needed |
|
|
129
|
+
| 5.0 | `const` type parameters | `<const T>` gives const-like inference without `as const` at call site |
|
|
130
|
+
| 5.1 | Easier implicit returns | `undefined`-returning functions can omit `return` |
|
|
131
|
+
| 5.2 | `using` declarations | Deterministic resource cleanup (like C# `using` / Python `with`) |
|
|
132
|
+
| 5.4 | `NoInfer<T>` | Prevents unwanted inference from specific positions |
|
|
133
|
+
| 5.5 | Inferred type predicates | `filter(Boolean)` and arrow guards just work |
|
|
134
|
+
| 5.6 | Iterator helper methods | `.map()`, `.filter()`, `.take()` on iterators |
|
|
135
|
+
| 5.7 | `--squash` for project refs | Faster composite project builds |
|
|
136
|
+
| 5.8 | `--erasableSyntaxOnly` | Strip types without full compilation (Node.js `--strip-types` support) |
|
|
137
|
+
|
|
138
|
+
## When to Read the References
|
|
139
|
+
|
|
140
|
+
- **Writing a new module/library**: Read [core-generics](references/core-generics.md) and [best-practices-patterns](references/best-practices-patterns.md)
|
|
141
|
+
- **Debugging a confusing type error**: Read [advanced-type-guards](references/advanced-type-guards.md) and [core-type-system](references/core-type-system.md)
|
|
142
|
+
- **Designing a type-safe API**: Read [advanced-conditional-types](references/advanced-conditional-types.md) and [advanced-mapped-types](references/advanced-mapped-types.md)
|
|
143
|
+
- **Setting up a new project**: Read [best-practices-tsconfig](references/best-practices-tsconfig.md)
|
|
144
|
+
- **Migrating from JS or older TS**: Read [features-ts5x](references/features-ts5x.md) and [best-practices-tsconfig](references/best-practices-tsconfig.md)
|
|
145
|
+
- **Performance issues with types**: Read [best-practices-performance](references/best-practices-performance.md)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run TypeScript type-checking and resolve all errors using the typescript-expert skill
|
|
3
|
+
allowed-tools: ["Read", "Edit", "Write", "Glob", "Grep", "Bash"]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are a TypeScript expert with deep expertise in advanced typing patterns, modern JavaScript (ES6+), and enterprise-grade development practices. You specialize in building reliable, maintainable, and performant TypeScript solutions for complex business problems, with a solid understanding of JavaScript fundamentals and code quality tools.
|
|
7
|
+
|
|
8
|
+
Use the `typescript-expert` skill for reference when resolving complex type issues — it covers generics, conditional types, mapped types, utility types, type guards, discriminated unions, and TypeScript 5.x features.
|
|
9
|
+
|
|
10
|
+
## Step 1: Detect the Project Setup
|
|
11
|
+
|
|
12
|
+
Read `package.json` to determine:
|
|
13
|
+
- The package manager in use (`npm`, `pnpm`, `yarn`, or `bun`) — check for lock files (`pnpm-lock.yaml`, `yarn.lock`, `bun.lockb`, `package-lock.json`)
|
|
14
|
+
- Whether a `typecheck` script exists in `scripts` (e.g., `"typecheck": "tsc --noEmit"`)
|
|
15
|
+
- The TypeScript version installed
|
|
16
|
+
- Any relevant type-checking plugins (e.g., `vue-tsc`, `astro check`)
|
|
17
|
+
|
|
18
|
+
Read `tsconfig.json` (and any extended configs like `tsconfig.app.json`) to understand:
|
|
19
|
+
- The `strict` settings in effect
|
|
20
|
+
- The `include`/`exclude` paths
|
|
21
|
+
- Module resolution strategy
|
|
22
|
+
- Any path aliases
|
|
23
|
+
|
|
24
|
+
## Step 2: Run Type-Checking
|
|
25
|
+
|
|
26
|
+
Run the appropriate command based on what you found:
|
|
27
|
+
|
|
28
|
+
1. **If a `typecheck` script exists**: `npm run typecheck` / `pnpm run typecheck` / `yarn typecheck`
|
|
29
|
+
2. **If no script but `tsc` is available**: `npx tsc --noEmit`
|
|
30
|
+
3. **For monorepos**: Check if there's a root-level typecheck or per-package scripts
|
|
31
|
+
|
|
32
|
+
Capture the full output. If there are no errors, report success and stop.
|
|
33
|
+
|
|
34
|
+
## Step 3: Analyze and Categorize Errors
|
|
35
|
+
|
|
36
|
+
Group errors by category before fixing:
|
|
37
|
+
|
|
38
|
+
- **Missing types**: `Cannot find module` or `Could not find a declaration file` — need `@types/*` packages or declaration files
|
|
39
|
+
- **Strict null violations**: `Object is possibly 'null' or 'undefined'` — need null checks or non-null assertions
|
|
40
|
+
- **Type mismatches**: `Type 'X' is not assignable to type 'Y'` — need type corrections, guards, or generics
|
|
41
|
+
- **Missing properties**: `Property 'X' does not exist on type 'Y'` — need interface extensions or type narrowing
|
|
42
|
+
- **Import issues**: `Module has no exported member` — need import corrections or type augmentation
|
|
43
|
+
- **Generic constraints**: `Type 'T' does not satisfy the constraint` — need constraint adjustments
|
|
44
|
+
|
|
45
|
+
## Step 4: Fix Errors Systematically
|
|
46
|
+
|
|
47
|
+
Work through errors file-by-file, starting with root causes (a single fix often resolves multiple downstream errors):
|
|
48
|
+
|
|
49
|
+
1. **Fix type declaration issues first** — missing `@types/*`, incorrect `d.ts` files, or module augmentations
|
|
50
|
+
2. **Fix interface/type definitions** — incorrect shapes propagate errors everywhere
|
|
51
|
+
3. **Fix implementation code** — narrowing, guards, assertions, generic constraints
|
|
52
|
+
4. **Fix edge cases** — strict null checks, index access, exhaustiveness
|
|
53
|
+
|
|
54
|
+
For each fix:
|
|
55
|
+
- Read the file and understand the context around the error
|
|
56
|
+
- Apply the minimal correct fix — don't over-annotate or use `any` as an escape hatch
|
|
57
|
+
- Prefer type narrowing and guards over type assertions (`as`)
|
|
58
|
+
- Use `unknown` instead of `any` when the type is truly unknown
|
|
59
|
+
- Add `// @ts-expect-error` only as a last resort, with a comment explaining why
|
|
60
|
+
|
|
61
|
+
## Step 5: Verify
|
|
62
|
+
|
|
63
|
+
Re-run the type-check command from Step 2. If errors remain, go back to Step 3 with the new output. Repeat until clean.
|
|
64
|
+
|
|
65
|
+
Report the final result: how many errors were found, how many were fixed, and what changes were made.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Conditional Types
|
|
2
|
+
|
|
3
|
+
Conditional types select one of two types based on a condition, enabling type-level logic similar to ternary expressions.
|
|
4
|
+
|
|
5
|
+
## Basic Syntax
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
type IsString<T> = T extends string ? true : false;
|
|
9
|
+
|
|
10
|
+
type A = IsString<"hello">; // true
|
|
11
|
+
type B = IsString<42>; // false
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The syntax is `T extends U ? X : Y` — if `T` is assignable to `U`, the result is `X`, otherwise `Y`.
|
|
15
|
+
|
|
16
|
+
## The `infer` Keyword
|
|
17
|
+
|
|
18
|
+
`infer` declares a type variable within a conditional type, extracting parts of a type:
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// Extract the element type from an array
|
|
22
|
+
type ElementType<T> = T extends (infer E)[] ? E : never;
|
|
23
|
+
type A = ElementType<string[]>; // string
|
|
24
|
+
type B = ElementType<number>; // never
|
|
25
|
+
|
|
26
|
+
// Extract the return type of a function
|
|
27
|
+
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
|
|
28
|
+
type C = MyReturnType<() => string>; // string
|
|
29
|
+
|
|
30
|
+
// Extract promise inner type
|
|
31
|
+
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
|
|
32
|
+
type D = UnwrapPromise<Promise<number>>; // number
|
|
33
|
+
type E = UnwrapPromise<string>; // string
|
|
34
|
+
|
|
35
|
+
// Multiple infer positions
|
|
36
|
+
type FirstArg<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never;
|
|
37
|
+
type F = FirstArg<(name: string, age: number) => void>; // string
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### `infer` with Constraints (TS 4.7+)
|
|
41
|
+
|
|
42
|
+
You can constrain what `infer` matches:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// Only infer if the element is a string
|
|
46
|
+
type StringElements<T> = T extends (infer E extends string)[] ? E : never;
|
|
47
|
+
type G = StringElements<["a", "b", "c"]>; // "a" | "b" | "c"
|
|
48
|
+
type H = StringElements<[1, 2, 3]>; // never
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Distributive Conditional Types
|
|
52
|
+
|
|
53
|
+
When a conditional type acts on a **naked type parameter** (not wrapped in `[]`, `Promise<>`, etc.), it distributes over union types:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
type ToArray<T> = T extends any ? T[] : never;
|
|
57
|
+
|
|
58
|
+
// Distributes: applies to each union member separately
|
|
59
|
+
type A = ToArray<string | number>; // string[] | number[]
|
|
60
|
+
|
|
61
|
+
// Compare with non-distributive version:
|
|
62
|
+
type ToArrayND<T> = [T] extends [any] ? T[] : never;
|
|
63
|
+
type B = ToArrayND<string | number>; // (string | number)[]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Preventing Distribution
|
|
67
|
+
|
|
68
|
+
Wrap both sides in `[]` to prevent distribution:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
type IsNever<T> = [T] extends [never] ? true : false;
|
|
72
|
+
|
|
73
|
+
type A = IsNever<never>; // true
|
|
74
|
+
type B = IsNever<string>; // false
|
|
75
|
+
|
|
76
|
+
// Without brackets, never distributes to... nothing
|
|
77
|
+
type IsNeverBad<T> = T extends never ? true : false;
|
|
78
|
+
type C = IsNeverBad<never>; // never (not true!)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Practical Patterns
|
|
82
|
+
|
|
83
|
+
### Filtering Union Members
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Keep only object types from a union
|
|
87
|
+
type ObjectsOnly<T> = T extends object ? T : never;
|
|
88
|
+
type Mixed = string | { a: 1 } | number | { b: 2 };
|
|
89
|
+
type OnlyObjects = ObjectsOnly<Mixed>; // { a: 1 } | { b: 2 }
|
|
90
|
+
|
|
91
|
+
// Keep only functions
|
|
92
|
+
type FunctionsOnly<T> = T extends (...args: any[]) => any ? T : never;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Recursive Conditional Types
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// Deeply unwrap promises
|
|
99
|
+
type DeepAwaited<T> = T extends Promise<infer U> ? DeepAwaited<U> : T;
|
|
100
|
+
type A = DeepAwaited<Promise<Promise<Promise<string>>>>; // string
|
|
101
|
+
|
|
102
|
+
// Flatten nested arrays
|
|
103
|
+
type Flatten<T> = T extends (infer E)[] ? Flatten<E> : T;
|
|
104
|
+
type B = Flatten<number[][][]>; // number
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Extracting Based on Shape
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// Extract event handlers from an object type
|
|
111
|
+
type EventHandlers<T> = {
|
|
112
|
+
[K in keyof T as T[K] extends (...args: any[]) => any ? K : never]: T[K];
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
interface Component {
|
|
116
|
+
onClick: (e: MouseEvent) => void;
|
|
117
|
+
onHover: (e: MouseEvent) => void;
|
|
118
|
+
className: string;
|
|
119
|
+
id: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
type Handlers = EventHandlers<Component>;
|
|
123
|
+
// { onClick: (e: MouseEvent) => void; onHover: (e: MouseEvent) => void }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Conditional Return Types
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// Function overload via conditional types
|
|
130
|
+
function process<T extends string | number>(
|
|
131
|
+
value: T
|
|
132
|
+
): T extends string ? string[] : number {
|
|
133
|
+
if (typeof value === "string") {
|
|
134
|
+
return value.split("") as any;
|
|
135
|
+
}
|
|
136
|
+
return (value * 2) as any;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const a = process("hello"); // string[]
|
|
140
|
+
const b = process(42); // number
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Note: Conditional return types often require `as any` inside the implementation because TypeScript can't narrow generic types. This is one of the few legitimate uses of `as any`.
|
|
144
|
+
|
|
145
|
+
### Type-Level Assertions
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Ensure a type satisfies a condition at the type level
|
|
149
|
+
type Assert<T extends true> = T;
|
|
150
|
+
type IsEqual<A, B> = [A] extends [B] ? [B] extends [A] ? true : false : false;
|
|
151
|
+
|
|
152
|
+
// Compile-time test
|
|
153
|
+
type _test = Assert<IsEqual<string, string>>; // OK
|
|
154
|
+
// type _test2 = Assert<IsEqual<string, number>>; // Error!
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Common Utility Implementations
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// Built-in Exclude
|
|
161
|
+
type MyExclude<T, U> = T extends U ? never : T;
|
|
162
|
+
|
|
163
|
+
// Built-in Extract
|
|
164
|
+
type MyExtract<T, U> = T extends U ? T : never;
|
|
165
|
+
|
|
166
|
+
// Built-in NonNullable
|
|
167
|
+
type MyNonNullable<T> = T extends null | undefined ? never : T;
|
|
168
|
+
|
|
169
|
+
// Built-in Parameters
|
|
170
|
+
type MyParameters<T extends (...args: any) => any> =
|
|
171
|
+
T extends (...args: infer P) => any ? P : never;
|
|
172
|
+
|
|
173
|
+
// Built-in ReturnType
|
|
174
|
+
type MyReturnType<T extends (...args: any) => any> =
|
|
175
|
+
T extends (...args: any) => infer R ? R : any;
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Gotchas
|
|
179
|
+
|
|
180
|
+
1. **`never` in conditionals**: `never` distributes to nothing. Use `[T] extends [never]` to check for never.
|
|
181
|
+
|
|
182
|
+
2. **`any` in conditionals**: `any` produces a union of both branches:
|
|
183
|
+
```typescript
|
|
184
|
+
type Test<T> = T extends string ? "yes" : "no";
|
|
185
|
+
type X = Test<any>; // "yes" | "no"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
3. **Depth limits**: TypeScript has a recursion depth limit (~50 levels). Deep recursive types may hit it.
|
|
189
|
+
|
|
190
|
+
4. **Assignability of conditional types**: TypeScript often can't resolve conditional types involving unresolved generics. Inside a generic function, `T extends X ? A : B` remains unresolved.
|