memory-journal-mcp 7.0.1 → 7.2.0
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 +75 -66
- package/dist/{chunk-6J4RPJ4I.js → chunk-GR4T3SRW.js} +146 -105
- package/dist/{chunk-ARLH46WS.js → chunk-IWKLHSPU.js} +89 -3
- package/dist/{chunk-2BJHLTYP.js → chunk-ORV7ZZOE.js} +1086 -86
- package/dist/cli.js +30 -4
- package/dist/github-integration-2TFMXHIJ.js +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +3 -3
- package/dist/{tools-FFFGXIKN.js → tools-CXR2FEB2.js} +2 -2
- package/package.json +2 -2
- package/skills/README.md +77 -0
- package/skills/autonomous-dev/SKILL.md +56 -0
- package/skills/bin/sync.js +50 -0
- package/skills/bun/SKILL.md +156 -0
- package/skills/github-commander/SKILL.md +1 -1
- package/skills/github-commander/workflows/code-quality-audit.md +7 -5
- package/skills/github-commander/workflows/issue-triage.md +13 -4
- package/skills/github-commander/workflows/milestone-sprint.md +9 -1
- package/skills/github-commander/workflows/perf-audit.md +2 -0
- package/skills/github-commander/workflows/pr-review.md +9 -3
- package/skills/github-commander/workflows/roadmap-kickoff.md +79 -0
- package/skills/github-commander/workflows/security-audit.md +3 -3
- package/skills/github-commander/workflows/update-deps.md +2 -2
- package/skills/gitlab/SKILL.md +115 -0
- package/skills/gitlab/package-lock.json +392 -0
- package/skills/gitlab/package.json +14 -0
- package/skills/gitlab/scripts/gitlab-client.ts +125 -0
- package/skills/gitlab/scripts/gitlab-helper.ts +80 -0
- package/skills/golang/SKILL.md +54 -0
- package/skills/mysql/SKILL.md +30 -0
- package/skills/package.json +48 -0
- package/skills/playwright-standard/SKILL.md +58 -0
- package/skills/playwright-standard/examples/fixtures.ts +66 -0
- package/skills/playwright-standard/examples/type-stubs.d.ts +10 -0
- package/skills/playwright-standard/references/advanced-scenarios.md +59 -0
- package/skills/playwright-standard/references/infrastructure.md +43 -0
- package/skills/postgres/SKILL.md +33 -0
- package/skills/react-best-practices/AGENTS.md +2883 -0
- package/skills/react-best-practices/README.md +127 -0
- package/skills/react-best-practices/SKILL.md +138 -0
- package/skills/react-best-practices/metadata.json +17 -0
- package/skills/react-best-practices/rules/_sections.md +46 -0
- package/skills/react-best-practices/rules/_template.md +28 -0
- package/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/skills/react-best-practices/rules/advanced-init-once.md +42 -0
- package/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/skills/react-best-practices/rules/async-api-routes.md +35 -0
- package/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/skills/react-best-practices/rules/async-dependencies.md +48 -0
- package/skills/react-best-practices/rules/async-parallel.md +24 -0
- package/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/skills/react-best-practices/rules/bundle-conditional.md +37 -0
- package/skills/react-best-practices/rules/bundle-defer-third-party.md +48 -0
- package/skills/react-best-practices/rules/bundle-dynamic-imports.md +34 -0
- package/skills/react-best-practices/rules/bundle-preload.md +44 -0
- package/skills/react-best-practices/rules/client-event-listeners.md +78 -0
- package/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
- package/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
- package/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/skills/react-best-practices/rules/js-cache-storage.md +68 -0
- package/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/skills/react-best-practices/rules/js-length-check-first.md +50 -0
- package/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/skills/react-best-practices/rules/rendering-activity.md +24 -0
- package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
- package/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
- package/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
- package/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +72 -0
- package/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +26 -0
- package/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
- package/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
- package/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
- package/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/skills/react-best-practices/rules/server-auth-actions.md +96 -0
- package/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/skills/react-best-practices/rules/server-dedup-props.md +65 -0
- package/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/skills/rust/SKILL.md +86 -0
- package/skills/shadcn-ui/SKILL.md +72 -0
- package/skills/skill-builder/SKILL.md +457 -0
- package/skills/skill-builder/checklist.md +65 -0
- package/skills/sqlite/SKILL.md +38 -0
- package/skills/typescript/SKILL.md +453 -0
- package/skills/typescript/assets/eslint-template.js +102 -0
- package/skills/typescript/assets/tsconfig-template.json +45 -0
- package/skills/typescript/references/enterprise-patterns.md +531 -0
- package/skills/typescript/references/generics.md +493 -0
- package/skills/typescript/references/nestjs-integration.md +579 -0
- package/skills/typescript/references/react-integration.md +616 -0
- package/skills/typescript/references/toolchain.md +547 -0
- package/skills/typescript/references/type-system.md +481 -0
- package/skills/vitest-standard/SKILL.md +82 -0
- package/skills/vitest-standard/examples/service-mock.ts +60 -0
- package/skills/vitest-standard/examples/tdd-calculator.ts +41 -0
- package/skills/vitest-standard/examples/type-stubs.d.ts +18 -0
- package/skills/vitest-standard/references/async-and-errors.md +58 -0
- package/skills/vitest-standard/references/coverage-and-config.md +53 -0
- package/skills/vitest-standard/references/mocking.md +61 -0
- package/skills/vitest-standard/references/tdd-patterns.md +60 -0
- package/dist/github-integration-PDRLXKGM.js +0 -1
- package/skills/github-commander/workflows/full-audit.md +0 -134
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# Generics Reference
|
|
2
|
+
|
|
3
|
+
> **Load when:** User asks about generics, mapped types, conditional types, template literal types, or reusable type patterns.
|
|
4
|
+
|
|
5
|
+
Advanced generics and type-level programming patterns.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- [Generic Fundamentals](#generic-fundamentals)
|
|
10
|
+
- [Generic Constraints](#generic-constraints)
|
|
11
|
+
- [Mapped Types](#mapped-types)
|
|
12
|
+
- [Conditional Types](#conditional-types)
|
|
13
|
+
- [Template Literal Types](#template-literal-types)
|
|
14
|
+
- [Variadic Tuple Types](#variadic-tuple-types)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Generic Fundamentals
|
|
19
|
+
|
|
20
|
+
### Basic Generic Function
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
// Type parameter T can be any type
|
|
24
|
+
function identity<T>(value: T): T {
|
|
25
|
+
return value
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const str = identity('hello') // string
|
|
29
|
+
const num = identity(42) // number
|
|
30
|
+
const obj = identity({ x: 1 }) // { x: number }
|
|
31
|
+
|
|
32
|
+
// Explicit type argument (rarely needed)
|
|
33
|
+
const explicit = identity<string>('hello')
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Generic Interfaces
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
interface Container<T> {
|
|
40
|
+
value: T
|
|
41
|
+
getValue(): T
|
|
42
|
+
setValue(value: T): void
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface Repository<T, ID = string> {
|
|
46
|
+
findById(id: ID): Promise<T | null>
|
|
47
|
+
findAll(): Promise<T[]>
|
|
48
|
+
save(entity: T): Promise<T>
|
|
49
|
+
delete(id: ID): Promise<boolean>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Implementation
|
|
53
|
+
class UserRepository implements Repository<User> {
|
|
54
|
+
async findById(id: string): Promise<User | null> {
|
|
55
|
+
// implementation
|
|
56
|
+
}
|
|
57
|
+
// ... other methods
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Generic Classes
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
class Stack<T> {
|
|
65
|
+
private items: T[] = []
|
|
66
|
+
|
|
67
|
+
push(item: T): void {
|
|
68
|
+
this.items.push(item)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pop(): T | undefined {
|
|
72
|
+
return this.items.pop()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
peek(): T | undefined {
|
|
76
|
+
return this.items[this.items.length - 1]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
isEmpty(): boolean {
|
|
80
|
+
return this.items.length === 0
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const numberStack = new Stack<number>()
|
|
85
|
+
numberStack.push(1)
|
|
86
|
+
numberStack.push(2)
|
|
87
|
+
const top = numberStack.pop() // number | undefined
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Generic Constraints
|
|
93
|
+
|
|
94
|
+
### extends Constraint
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// T must have a length property
|
|
98
|
+
interface HasLength {
|
|
99
|
+
length: number
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function logLength<T extends HasLength>(item: T): T {
|
|
103
|
+
console.log(`Length: ${item.length}`)
|
|
104
|
+
return item
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
logLength('hello') // OK: string has length
|
|
108
|
+
logLength([1, 2, 3]) // OK: array has length
|
|
109
|
+
logLength({ length: 10 }) // OK: object has length
|
|
110
|
+
logLength(42) // Error: number has no length
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### keyof Constraint
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
|
|
117
|
+
return obj[key]
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface Person {
|
|
121
|
+
name: string
|
|
122
|
+
age: number
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const person: Person = { name: 'Alice', age: 30 }
|
|
126
|
+
|
|
127
|
+
const name = getProperty(person, 'name') // string
|
|
128
|
+
const age = getProperty(person, 'age') // number
|
|
129
|
+
const bad = getProperty(person, 'email') // Error: "email" not in Person
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Multiple Constraints
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
interface Printable {
|
|
136
|
+
print(): void
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
interface Loggable {
|
|
140
|
+
log(): string
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// T must satisfy both interfaces
|
|
144
|
+
function process<T extends Printable & Loggable>(item: T): void {
|
|
145
|
+
item.print()
|
|
146
|
+
console.log(item.log())
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Default Type Parameters
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
interface ApiResponse<T = unknown, E = Error> {
|
|
154
|
+
data?: T
|
|
155
|
+
error?: E
|
|
156
|
+
status: number
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Uses defaults
|
|
160
|
+
const response1: ApiResponse = { status: 200 }
|
|
161
|
+
|
|
162
|
+
// Override data type only
|
|
163
|
+
const response2: ApiResponse<User> = { data: user, status: 200 }
|
|
164
|
+
|
|
165
|
+
// Override both
|
|
166
|
+
const response3: ApiResponse<User, ValidationError> = {
|
|
167
|
+
error: new ValidationError(),
|
|
168
|
+
status: 400,
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Mapped Types
|
|
175
|
+
|
|
176
|
+
### Basic Mapped Types
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// Transform all properties to optional
|
|
180
|
+
type Partial<T> = {
|
|
181
|
+
[K in keyof T]?: T[K]
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Transform all properties to required
|
|
185
|
+
type Required<T> = {
|
|
186
|
+
[K in keyof T]-?: T[K]
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Transform all properties to readonly
|
|
190
|
+
type Readonly<T> = {
|
|
191
|
+
readonly [K in keyof T]: T[K]
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Remove readonly modifier
|
|
195
|
+
type Mutable<T> = {
|
|
196
|
+
-readonly [K in keyof T]: T[K]
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Practical Mapped Types
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// Make all properties nullable
|
|
204
|
+
type Nullable<T> = {
|
|
205
|
+
[K in keyof T]: T[K] | null
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Make all properties async getters
|
|
209
|
+
type AsyncGetters<T> = {
|
|
210
|
+
[K in keyof T as `get${Capitalize<string & K>}`]: () => Promise<T[K]>
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
interface User {
|
|
214
|
+
name: string
|
|
215
|
+
email: string
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
type UserGetters = AsyncGetters<User>
|
|
219
|
+
// {
|
|
220
|
+
// getName: () => Promise<string>;
|
|
221
|
+
// getEmail: () => Promise<string>;
|
|
222
|
+
// }
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Key Remapping (as clause)
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
// Filter keys by type
|
|
229
|
+
type FilterByType<T, U> = {
|
|
230
|
+
[K in keyof T as T[K] extends U ? K : never]: T[K]
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
interface Mixed {
|
|
234
|
+
name: string
|
|
235
|
+
age: number
|
|
236
|
+
active: boolean
|
|
237
|
+
score: number
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
type StringProps = FilterByType<Mixed, string>
|
|
241
|
+
// { name: string }
|
|
242
|
+
|
|
243
|
+
type NumberProps = FilterByType<Mixed, number>
|
|
244
|
+
// { age: number; score: number }
|
|
245
|
+
|
|
246
|
+
// Prefix all keys
|
|
247
|
+
type Prefixed<T, P extends string> = {
|
|
248
|
+
[K in keyof T as `${P}${Capitalize<string & K>}`]: T[K]
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
type PrefixedUser = Prefixed<User, 'user'>
|
|
252
|
+
// { userName: string; userEmail: string }
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Conditional Types
|
|
258
|
+
|
|
259
|
+
### Basic Conditional Types
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
// T extends U ? X : Y
|
|
263
|
+
type IsString<T> = T extends string ? true : false
|
|
264
|
+
|
|
265
|
+
type A = IsString<string> // true
|
|
266
|
+
type B = IsString<number> // false
|
|
267
|
+
type C = IsString<'hello'> // true
|
|
268
|
+
|
|
269
|
+
// Practical: Extract non-nullable type
|
|
270
|
+
type NonNullable<T> = T extends null | undefined ? never : T
|
|
271
|
+
|
|
272
|
+
type D = NonNullable<string | null> // string
|
|
273
|
+
type E = NonNullable<number | undefined> // number
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Distributive Conditional Types
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
// Conditional types distribute over unions
|
|
280
|
+
type ToArray<T> = T extends unknown ? T[] : never
|
|
281
|
+
|
|
282
|
+
type StringOrNumberArray = ToArray<string | number>
|
|
283
|
+
// string[] | number[] (not (string | number)[])
|
|
284
|
+
|
|
285
|
+
// Prevent distribution with tuple
|
|
286
|
+
type ToArrayNonDist<T> = [T] extends [unknown] ? T[] : never
|
|
287
|
+
|
|
288
|
+
type Mixed = ToArrayNonDist<string | number>
|
|
289
|
+
// (string | number)[]
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### infer Keyword
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
// Extract return type
|
|
296
|
+
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never
|
|
297
|
+
|
|
298
|
+
type FnReturn = ReturnType<() => string> // string
|
|
299
|
+
|
|
300
|
+
// Extract array element type
|
|
301
|
+
type ArrayElement<T> = T extends (infer E)[] ? E : never
|
|
302
|
+
|
|
303
|
+
type Element = ArrayElement<number[]> // number
|
|
304
|
+
|
|
305
|
+
// Extract Promise result
|
|
306
|
+
type Awaited<T> = T extends Promise<infer R> ? Awaited<R> : T
|
|
307
|
+
|
|
308
|
+
type Result = Awaited<Promise<Promise<string>>> // string
|
|
309
|
+
|
|
310
|
+
// Extract function first parameter
|
|
311
|
+
type FirstParam<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never
|
|
312
|
+
|
|
313
|
+
type First = FirstParam<(name: string, age: number) => void> // string
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Practical Conditional Types
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
// API response helper
|
|
320
|
+
type ApiResult<T> = { success: true; data: T } | { success: false; error: string }
|
|
321
|
+
|
|
322
|
+
// Extract data type from result
|
|
323
|
+
type ExtractData<T> = T extends { success: true; data: infer D } ? D : never
|
|
324
|
+
|
|
325
|
+
type UserResult = ApiResult<User>
|
|
326
|
+
type UserData = ExtractData<UserResult> // User
|
|
327
|
+
|
|
328
|
+
// Type-safe event handlers
|
|
329
|
+
type EventHandler<T> = T extends `on${infer Event}` ? (event: Event) => void : never
|
|
330
|
+
|
|
331
|
+
type ClickHandler = EventHandler<'onClick'> // (event: "Click") => void
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Template Literal Types
|
|
337
|
+
|
|
338
|
+
### Basic Template Literals
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
type Greeting = `Hello, ${string}!`
|
|
342
|
+
|
|
343
|
+
const valid: Greeting = 'Hello, World!' // OK
|
|
344
|
+
const invalid: Greeting = 'Hi, World!' // Error
|
|
345
|
+
|
|
346
|
+
// Combine with unions
|
|
347
|
+
type Size = 'small' | 'medium' | 'large'
|
|
348
|
+
type Color = 'red' | 'blue' | 'green'
|
|
349
|
+
|
|
350
|
+
type ColoredSize = `${Color}-${Size}`
|
|
351
|
+
// "red-small" | "red-medium" | "red-large" |
|
|
352
|
+
// "blue-small" | "blue-medium" | "blue-large" |
|
|
353
|
+
// "green-small" | "green-medium" | "green-large"
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### String Manipulation Types
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
// Built-in string manipulation types
|
|
360
|
+
type Upper = Uppercase<'hello'> // "HELLO"
|
|
361
|
+
type Lower = Lowercase<'HELLO'> // "hello"
|
|
362
|
+
type Cap = Capitalize<'hello'> // "Hello"
|
|
363
|
+
type Uncap = Uncapitalize<'Hello'> // "hello"
|
|
364
|
+
|
|
365
|
+
// Practical: Generate event names
|
|
366
|
+
type Event = 'click' | 'hover' | 'focus'
|
|
367
|
+
type EventHandler = `on${Capitalize<Event>}`
|
|
368
|
+
// "onClick" | "onHover" | "onFocus"
|
|
369
|
+
|
|
370
|
+
// CSS property with vendor prefixes
|
|
371
|
+
type CSSProp = 'transform' | 'transition'
|
|
372
|
+
type Prefixed = `-webkit-${CSSProp}` | `-moz-${CSSProp}` | CSSProp
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Advanced Template Patterns
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
// Parse dot-notation paths
|
|
379
|
+
type PathSegment<T> = T extends `${infer Head}.${infer Tail}` ? Head | PathSegment<Tail> : T
|
|
380
|
+
|
|
381
|
+
type Segments = PathSegment<'user.profile.name'>
|
|
382
|
+
// "user" | "profile" | "name"
|
|
383
|
+
|
|
384
|
+
// HTTP methods with paths
|
|
385
|
+
type Method = 'GET' | 'POST' | 'PUT' | 'DELETE'
|
|
386
|
+
type Endpoint = '/users' | '/posts' | '/comments'
|
|
387
|
+
|
|
388
|
+
type Route = `${Method} ${Endpoint}`
|
|
389
|
+
// "GET /users" | "GET /posts" | "GET /comments" |
|
|
390
|
+
// "POST /users" | ... etc
|
|
391
|
+
|
|
392
|
+
// Type-safe SQL column references
|
|
393
|
+
type Table = 'users' | 'posts'
|
|
394
|
+
type Column<T extends Table> = T extends 'users'
|
|
395
|
+
? 'id' | 'name' | 'email'
|
|
396
|
+
: T extends 'posts'
|
|
397
|
+
? 'id' | 'title' | 'content'
|
|
398
|
+
: never
|
|
399
|
+
|
|
400
|
+
type UserColumn = `users.${Column<'users'>}`
|
|
401
|
+
// "users.id" | "users.name" | "users.email"
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Variadic Tuple Types
|
|
407
|
+
|
|
408
|
+
### Basic Variadic Tuples
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
// Spread tuple types
|
|
412
|
+
type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U]
|
|
413
|
+
|
|
414
|
+
type Combined = Concat<[1, 2], [3, 4]>
|
|
415
|
+
// [1, 2, 3, 4]
|
|
416
|
+
|
|
417
|
+
// Prepend element
|
|
418
|
+
type Prepend<T, U extends unknown[]> = [T, ...U]
|
|
419
|
+
|
|
420
|
+
type WithFirst = Prepend<0, [1, 2, 3]>
|
|
421
|
+
// [0, 1, 2, 3]
|
|
422
|
+
|
|
423
|
+
// Append element
|
|
424
|
+
type Append<T extends unknown[], U> = [...T, U]
|
|
425
|
+
|
|
426
|
+
type WithLast = Append<[1, 2, 3], 4>
|
|
427
|
+
// [1, 2, 3, 4]
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Practical Variadic Patterns
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
// Typed curry function
|
|
434
|
+
type Curry<F> = F extends (...args: infer A) => infer R
|
|
435
|
+
? A extends [infer First, ...infer Rest]
|
|
436
|
+
? (arg: First) => Curry<(...args: Rest) => R>
|
|
437
|
+
: R
|
|
438
|
+
: never
|
|
439
|
+
|
|
440
|
+
declare function curry<F extends (...args: any[]) => any>(fn: F): Curry<F>
|
|
441
|
+
|
|
442
|
+
function add(a: number, b: number, c: number): number {
|
|
443
|
+
return a + b + c
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const curriedAdd = curry(add)
|
|
447
|
+
const add1 = curriedAdd(1) // (arg: number) => Curry<...>
|
|
448
|
+
const add1and2 = add1(2) // (arg: number) => number
|
|
449
|
+
const result = add1and2(3) // number (6)
|
|
450
|
+
|
|
451
|
+
// Typed pipe function
|
|
452
|
+
type Pipe<T extends unknown[], R> = T extends [infer First, ...infer Rest]
|
|
453
|
+
? First extends (arg: R) => infer Next
|
|
454
|
+
? Pipe<Rest, Next>
|
|
455
|
+
: never
|
|
456
|
+
: R
|
|
457
|
+
|
|
458
|
+
function pipe<T extends ((arg: any) => any)[]>(
|
|
459
|
+
...fns: T
|
|
460
|
+
): (arg: Parameters<T[0]>[0]) => Pipe<T, Parameters<T[0]>[0]> {
|
|
461
|
+
return (arg) => fns.reduce((acc, fn) => fn(acc), arg)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const process = pipe(
|
|
465
|
+
(n: number) => n * 2,
|
|
466
|
+
(n: number) => n.toString(),
|
|
467
|
+
(s: string) => s.length
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
const length = process(5) // number (2 - length of "10")
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Built-in Utility Types Reference
|
|
476
|
+
|
|
477
|
+
| Utility | Purpose | Example |
|
|
478
|
+
| -------------------------- | ----------------------- | ------------------------------------ |
|
|
479
|
+
| `Partial<T>` | All properties optional | `Partial<User>` |
|
|
480
|
+
| `Required<T>` | All properties required | `Required<Partial<User>>` |
|
|
481
|
+
| `Readonly<T>` | All properties readonly | `Readonly<User>` |
|
|
482
|
+
| `Pick<T, K>` | Select properties | `Pick<User, "id" \| "name">` |
|
|
483
|
+
| `Omit<T, K>` | Exclude properties | `Omit<User, "password">` |
|
|
484
|
+
| `Record<K, V>` | Create object type | `Record<string, User>` |
|
|
485
|
+
| `Exclude<T, U>` | Remove union members | `Exclude<"a" \| "b", "a">` |
|
|
486
|
+
| `Extract<T, U>` | Keep union members | `Extract<"a" \| "b", "a">` |
|
|
487
|
+
| `NonNullable<T>` | Remove null/undefined | `NonNullable<string \| null>` |
|
|
488
|
+
| `Parameters<F>` | Function parameters | `Parameters<typeof fn>` |
|
|
489
|
+
| `ReturnType<F>` | Function return | `ReturnType<typeof fn>` |
|
|
490
|
+
| `ConstructorParameters<C>` | Constructor params | `ConstructorParameters<typeof Date>` |
|
|
491
|
+
| `InstanceType<C>` | Instance type | `InstanceType<typeof Date>` |
|
|
492
|
+
| `Awaited<T>` | Unwrap Promise | `Awaited<Promise<User>>` |
|
|
493
|
+
| `NoInfer<T>` | Prevent inference | `NoInfer<T>` (TS 5.4+) |
|