agcel 1.0.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/.agent/workflows/api-gen.md +59 -0
- package/.agent/workflows/architect.md +44 -0
- package/.agent/workflows/brainstorm.md +223 -0
- package/.agent/workflows/build.md +38 -0
- package/.agent/workflows/changelog.md +51 -0
- package/.agent/workflows/checkpoint.md +138 -0
- package/.agent/workflows/commit.md +223 -0
- package/.agent/workflows/debug.md +57 -0
- package/.agent/workflows/deploy.md +76 -0
- package/.agent/workflows/doc.md +247 -0
- package/.agent/workflows/execute-plan.md +225 -0
- package/.agent/workflows/feature.md +255 -0
- package/.agent/workflows/fix.md +323 -0
- package/.agent/workflows/help.md +63 -0
- package/.agent/workflows/index.md +148 -0
- package/.agent/workflows/load.md +112 -0
- package/.agent/workflows/mode.md +170 -0
- package/.agent/workflows/optimize.md +53 -0
- package/.agent/workflows/plan.md +337 -0
- package/.agent/workflows/pr.md +74 -0
- package/.agent/workflows/product-plan.md +36 -0
- package/.agent/workflows/production-deploy.md +39 -0
- package/.agent/workflows/refactor.md +63 -0
- package/.agent/workflows/research.md +116 -0
- package/.agent/workflows/review.md +344 -0
- package/.agent/workflows/security-scan.md +56 -0
- package/.agent/workflows/ship.md +221 -0
- package/.agent/workflows/spawn.md +177 -0
- package/.agent/workflows/status.md +59 -0
- package/.agent/workflows/tdd.md +139 -0
- package/.agent/workflows/test.md +340 -0
- package/.agent/workflows/verify.md +35 -0
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/commands/init.js +142 -0
- package/dist/commands/install.js +98 -0
- package/dist/commands/list.js +49 -0
- package/dist/commands/restart.js +17 -0
- package/dist/commands/start.js +41 -0
- package/dist/commands/status.js +24 -0
- package/dist/commands/stop.js +29 -0
- package/dist/commands/uninstall.js +78 -0
- package/dist/index.js +58 -0
- package/dist/server/index.js +174 -0
- package/dist/utils/index.js +63 -0
- package/package.json +54 -0
- package/skills/api-security-best-practices/SKILL.md +291 -0
- package/skills/api-security-best-practices/references/examples.md +617 -0
- package/skills/architecture/SKILL.md +59 -0
- package/skills/architecture/context-discovery.md +43 -0
- package/skills/architecture/examples.md +94 -0
- package/skills/architecture/pattern-selection.md +68 -0
- package/skills/architecture/patterns-reference.md +50 -0
- package/skills/architecture/trade-off-analysis.md +77 -0
- package/skills/aws-serverless/SKILL.md +327 -0
- package/skills/brainstorming/SKILL.md +234 -0
- package/skills/c4-context/SKILL.md +154 -0
- package/skills/ci-cd-engineer/SKILL.md +50 -0
- package/skills/code-auditing/SKILL.md +55 -0
- package/skills/copywriting/SKILL.md +248 -0
- package/skills/database-engineer/SKILL.md +47 -0
- package/skills/doc-coauthoring/SKILL.md +379 -0
- package/skills/docker-expert/SKILL.md +412 -0
- package/skills/langgraph/SKILL.md +291 -0
- package/skills/postgresql/SKILL.md +73 -0
- package/skills/pricing-strategy/SKILL.md +360 -0
- package/skills/product-manager/SKILL.md +57 -0
- package/skills/prompt-engineer/README.md +659 -0
- package/skills/prompt-engineer/SKILL.md +256 -0
- package/skills/python-patterns/SKILL.md +445 -0
- package/skills/qa-engineer/SKILL.md +42 -0
- package/skills/rag-engineer/SKILL.md +94 -0
- package/skills/react-patterns/SKILL.md +202 -0
- package/skills/secure-refactoring/SKILL.md +54 -0
- package/skills/security-documentation/SKILL.md +53 -0
- package/skills/senior-architect/SKILL.md +213 -0
- package/skills/senior-architect/references/architecture_patterns.md +103 -0
- package/skills/senior-architect/references/system_design_workflows.md +103 -0
- package/skills/senior-architect/references/tech_decision_guide.md +103 -0
- package/skills/senior-architect/scripts/architecture_diagram_generator.py +114 -0
- package/skills/senior-architect/scripts/dependency_analyzer.py +114 -0
- package/skills/senior-architect/scripts/project_architect.py +114 -0
- package/skills/seo-audit/SKILL.md +491 -0
- package/skills/sql-injection-testing/SKILL.md +452 -0
- package/skills/test-driven-development/SKILL.md +375 -0
- package/skills/test-driven-development/testing-anti-patterns.md +299 -0
- package/skills/test-fixing/SKILL.md +123 -0
- package/skills/testing-patterns/SKILL.md +263 -0
- package/skills/typescript-expert/SKILL.md +202 -0
- package/skills/typescript-expert/references/advanced-topics.md +252 -0
- package/skills/typescript-expert/references/tsconfig-strict.json +92 -0
- package/skills/typescript-expert/references/typescript-cheatsheet.md +383 -0
- package/skills/typescript-expert/references/utility-types.ts +335 -0
- package/skills/typescript-expert/scripts/ts_diagnostic.py +203 -0
- package/skills/ui-ux-designer/SKILL.md +46 -0
- package/skills/vercel-deployment/SKILL.md +83 -0
- package/skills/vulnerability-scanner/SKILL.md +280 -0
- package/skills/vulnerability-scanner/checklists.md +121 -0
- package/skills/vulnerability-scanner/scripts/security_scan.py +458 -0
- package/skills/writing-plans/SKILL.md +120 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# TypeScript Cheatsheet
|
|
2
|
+
|
|
3
|
+
## Type Basics
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// Primitives
|
|
7
|
+
const name: string = 'John'
|
|
8
|
+
const age: number = 30
|
|
9
|
+
const isActive: boolean = true
|
|
10
|
+
const nothing: null = null
|
|
11
|
+
const notDefined: undefined = undefined
|
|
12
|
+
|
|
13
|
+
// Arrays
|
|
14
|
+
const numbers: number[] = [1, 2, 3]
|
|
15
|
+
const strings: Array<string> = ['a', 'b', 'c']
|
|
16
|
+
|
|
17
|
+
// Tuple
|
|
18
|
+
const tuple: [string, number] = ['hello', 42]
|
|
19
|
+
|
|
20
|
+
// Object
|
|
21
|
+
const user: { name: string; age: number } = { name: 'John', age: 30 }
|
|
22
|
+
|
|
23
|
+
// Union
|
|
24
|
+
const value: string | number = 'hello'
|
|
25
|
+
|
|
26
|
+
// Literal
|
|
27
|
+
const direction: 'up' | 'down' | 'left' | 'right' = 'up'
|
|
28
|
+
|
|
29
|
+
// Any vs Unknown
|
|
30
|
+
const anyValue: any = 'anything' // ❌ Avoid
|
|
31
|
+
const unknownValue: unknown = 'safe' // ✅ Prefer, requires narrowing
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Type Aliases & Interfaces
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// Type Alias
|
|
38
|
+
type Point = {
|
|
39
|
+
x: number
|
|
40
|
+
y: number
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Interface (preferred for objects)
|
|
44
|
+
interface User {
|
|
45
|
+
id: string
|
|
46
|
+
name: string
|
|
47
|
+
email?: string // Optional
|
|
48
|
+
readonly createdAt: Date // Readonly
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Extending
|
|
52
|
+
interface Admin extends User {
|
|
53
|
+
permissions: string[]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Intersection
|
|
57
|
+
type AdminUser = User & { permissions: string[] }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Generics
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Generic function
|
|
64
|
+
function identity<T>(value: T): T {
|
|
65
|
+
return value
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Generic with constraint
|
|
69
|
+
function getLength<T extends { length: number }>(item: T): number {
|
|
70
|
+
return item.length
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Generic interface
|
|
74
|
+
interface ApiResponse<T> {
|
|
75
|
+
data: T
|
|
76
|
+
status: number
|
|
77
|
+
message: string
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Generic with default
|
|
81
|
+
type Container<T = string> = {
|
|
82
|
+
value: T
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Multiple generics
|
|
86
|
+
function merge<T, U>(obj1: T, obj2: U): T & U {
|
|
87
|
+
return { ...obj1, ...obj2 }
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Utility Types
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
interface User {
|
|
95
|
+
id: string
|
|
96
|
+
name: string
|
|
97
|
+
email: string
|
|
98
|
+
age: number
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Partial - all optional
|
|
102
|
+
type PartialUser = Partial<User>
|
|
103
|
+
|
|
104
|
+
// Required - all required
|
|
105
|
+
type RequiredUser = Required<User>
|
|
106
|
+
|
|
107
|
+
// Readonly - all readonly
|
|
108
|
+
type ReadonlyUser = Readonly<User>
|
|
109
|
+
|
|
110
|
+
// Pick - select properties
|
|
111
|
+
type UserName = Pick<User, 'id' | 'name'>
|
|
112
|
+
|
|
113
|
+
// Omit - exclude properties
|
|
114
|
+
type UserWithoutEmail = Omit<User, 'email'>
|
|
115
|
+
|
|
116
|
+
// Record - key-value map
|
|
117
|
+
type UserMap = Record<string, User>
|
|
118
|
+
|
|
119
|
+
// Extract - extract from union
|
|
120
|
+
type StringOrNumber = string | number | boolean
|
|
121
|
+
type OnlyStrings = Extract<StringOrNumber, string>
|
|
122
|
+
|
|
123
|
+
// Exclude - exclude from union
|
|
124
|
+
type NotString = Exclude<StringOrNumber, string>
|
|
125
|
+
|
|
126
|
+
// NonNullable - remove null/undefined
|
|
127
|
+
type MaybeString = string | null | undefined
|
|
128
|
+
type DefinitelyString = NonNullable<MaybeString>
|
|
129
|
+
|
|
130
|
+
// ReturnType - get function return type
|
|
131
|
+
function getUser() { return { name: 'John' } }
|
|
132
|
+
type UserReturn = ReturnType<typeof getUser>
|
|
133
|
+
|
|
134
|
+
// Parameters - get function parameters
|
|
135
|
+
type GetUserParams = Parameters<typeof getUser>
|
|
136
|
+
|
|
137
|
+
// Awaited - unwrap Promise
|
|
138
|
+
type ResolvedUser = Awaited<Promise<User>>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Conditional Types
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Basic conditional
|
|
145
|
+
type IsString<T> = T extends string ? true : false
|
|
146
|
+
|
|
147
|
+
// Infer keyword
|
|
148
|
+
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T
|
|
149
|
+
|
|
150
|
+
// Distributive conditional
|
|
151
|
+
type ToArray<T> = T extends any ? T[] : never
|
|
152
|
+
type Result = ToArray<string | number> // string[] | number[]
|
|
153
|
+
|
|
154
|
+
// NonDistributive
|
|
155
|
+
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Template Literal Types
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
type Color = 'red' | 'green' | 'blue'
|
|
162
|
+
type Size = 'small' | 'medium' | 'large'
|
|
163
|
+
|
|
164
|
+
// Combine
|
|
165
|
+
type ColorSize = `${Color}-${Size}`
|
|
166
|
+
// 'red-small' | 'red-medium' | 'red-large' | ...
|
|
167
|
+
|
|
168
|
+
// Event handlers
|
|
169
|
+
type EventName = 'click' | 'focus' | 'blur'
|
|
170
|
+
type EventHandler = `on${Capitalize<EventName>}`
|
|
171
|
+
// 'onClick' | 'onFocus' | 'onBlur'
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Mapped Types
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
// Basic mapped type
|
|
178
|
+
type Optional<T> = {
|
|
179
|
+
[K in keyof T]?: T[K]
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// With key remapping
|
|
183
|
+
type Getters<T> = {
|
|
184
|
+
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Filter keys
|
|
188
|
+
type OnlyStrings<T> = {
|
|
189
|
+
[K in keyof T as T[K] extends string ? K : never]: T[K]
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Type Guards
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// typeof guard
|
|
197
|
+
function process(value: string | number) {
|
|
198
|
+
if (typeof value === 'string') {
|
|
199
|
+
return value.toUpperCase() // string
|
|
200
|
+
}
|
|
201
|
+
return value.toFixed(2) // number
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// instanceof guard
|
|
205
|
+
class Dog { bark() {} }
|
|
206
|
+
class Cat { meow() {} }
|
|
207
|
+
|
|
208
|
+
function makeSound(animal: Dog | Cat) {
|
|
209
|
+
if (animal instanceof Dog) {
|
|
210
|
+
animal.bark()
|
|
211
|
+
} else {
|
|
212
|
+
animal.meow()
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// in guard
|
|
217
|
+
interface Bird { fly(): void }
|
|
218
|
+
interface Fish { swim(): void }
|
|
219
|
+
|
|
220
|
+
function move(animal: Bird | Fish) {
|
|
221
|
+
if ('fly' in animal) {
|
|
222
|
+
animal.fly()
|
|
223
|
+
} else {
|
|
224
|
+
animal.swim()
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Custom type guard
|
|
229
|
+
function isString(value: unknown): value is string {
|
|
230
|
+
return typeof value === 'string'
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Assertion function
|
|
234
|
+
function assertIsString(value: unknown): asserts value is string {
|
|
235
|
+
if (typeof value !== 'string') {
|
|
236
|
+
throw new Error('Not a string')
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Discriminated Unions
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
// With type discriminant
|
|
245
|
+
type Success<T> = { type: 'success'; data: T }
|
|
246
|
+
type Error = { type: 'error'; message: string }
|
|
247
|
+
type Loading = { type: 'loading' }
|
|
248
|
+
|
|
249
|
+
type State<T> = Success<T> | Error | Loading
|
|
250
|
+
|
|
251
|
+
function handle<T>(state: State<T>) {
|
|
252
|
+
switch (state.type) {
|
|
253
|
+
case 'success':
|
|
254
|
+
return state.data // T
|
|
255
|
+
case 'error':
|
|
256
|
+
return state.message // string
|
|
257
|
+
case 'loading':
|
|
258
|
+
return null
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Exhaustive check
|
|
263
|
+
function assertNever(value: never): never {
|
|
264
|
+
throw new Error(`Unexpected value: ${value}`)
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Branded Types
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// Create branded type
|
|
272
|
+
type Brand<K, T> = K & { __brand: T }
|
|
273
|
+
|
|
274
|
+
type UserId = Brand<string, 'UserId'>
|
|
275
|
+
type OrderId = Brand<string, 'OrderId'>
|
|
276
|
+
|
|
277
|
+
// Constructor functions
|
|
278
|
+
function createUserId(id: string): UserId {
|
|
279
|
+
return id as UserId
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function createOrderId(id: string): OrderId {
|
|
283
|
+
return id as OrderId
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Usage - prevents mixing
|
|
287
|
+
function getOrder(orderId: OrderId, userId: UserId) {}
|
|
288
|
+
|
|
289
|
+
const userId = createUserId('user-123')
|
|
290
|
+
const orderId = createOrderId('order-456')
|
|
291
|
+
|
|
292
|
+
getOrder(orderId, userId) // ✅ OK
|
|
293
|
+
// getOrder(userId, orderId) // ❌ Error - types don't match
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Module Declarations
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// Declare module for untyped package
|
|
300
|
+
declare module 'untyped-package' {
|
|
301
|
+
export function doSomething(): void
|
|
302
|
+
export const value: string
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Augment existing module
|
|
306
|
+
declare module 'express' {
|
|
307
|
+
interface Request {
|
|
308
|
+
user?: { id: string }
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Declare global
|
|
313
|
+
declare global {
|
|
314
|
+
interface Window {
|
|
315
|
+
myGlobal: string
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## TSConfig Essentials
|
|
321
|
+
|
|
322
|
+
```json
|
|
323
|
+
{
|
|
324
|
+
"compilerOptions": {
|
|
325
|
+
// Strictness
|
|
326
|
+
"strict": true,
|
|
327
|
+
"noUncheckedIndexedAccess": true,
|
|
328
|
+
"noImplicitOverride": true,
|
|
329
|
+
|
|
330
|
+
// Modules
|
|
331
|
+
"module": "ESNext",
|
|
332
|
+
"moduleResolution": "bundler",
|
|
333
|
+
"esModuleInterop": true,
|
|
334
|
+
|
|
335
|
+
// Output
|
|
336
|
+
"target": "ES2022",
|
|
337
|
+
"lib": ["ES2022", "DOM"],
|
|
338
|
+
|
|
339
|
+
// Performance
|
|
340
|
+
"skipLibCheck": true,
|
|
341
|
+
"incremental": true,
|
|
342
|
+
|
|
343
|
+
// Paths
|
|
344
|
+
"baseUrl": ".",
|
|
345
|
+
"paths": {
|
|
346
|
+
"@/*": ["./src/*"]
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Best Practices
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
// ✅ Prefer interface for objects
|
|
356
|
+
interface User {
|
|
357
|
+
name: string
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ✅ Use const assertions
|
|
361
|
+
const routes = ['home', 'about'] as const
|
|
362
|
+
|
|
363
|
+
// ✅ Use satisfies for validation
|
|
364
|
+
const config = {
|
|
365
|
+
api: 'https://api.example.com'
|
|
366
|
+
} satisfies Record<string, string>
|
|
367
|
+
|
|
368
|
+
// ✅ Use unknown over any
|
|
369
|
+
function parse(input: unknown) {
|
|
370
|
+
if (typeof input === 'string') {
|
|
371
|
+
return JSON.parse(input)
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// ✅ Explicit return types for public APIs
|
|
376
|
+
export function getUser(id: string): User | null {
|
|
377
|
+
// ...
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// ❌ Avoid
|
|
381
|
+
const data: any = fetchData()
|
|
382
|
+
data.anything.goes.wrong // No type safety
|
|
383
|
+
```
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript Utility Types Library
|
|
3
|
+
*
|
|
4
|
+
* A collection of commonly used utility types for TypeScript projects.
|
|
5
|
+
* Copy and use as needed in your projects.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// BRANDED TYPES
|
|
10
|
+
// =============================================================================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create nominal/branded types to prevent primitive obsession.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* type UserId = Brand<string, 'UserId'>
|
|
17
|
+
* type OrderId = Brand<string, 'OrderId'>
|
|
18
|
+
*/
|
|
19
|
+
export type Brand<K, T> = K & { readonly __brand: T }
|
|
20
|
+
|
|
21
|
+
// Branded type constructors
|
|
22
|
+
export type UserId = Brand<string, 'UserId'>
|
|
23
|
+
export type Email = Brand<string, 'Email'>
|
|
24
|
+
export type UUID = Brand<string, 'UUID'>
|
|
25
|
+
export type Timestamp = Brand<number, 'Timestamp'>
|
|
26
|
+
export type PositiveNumber = Brand<number, 'PositiveNumber'>
|
|
27
|
+
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// RESULT TYPE (Error Handling)
|
|
30
|
+
// =============================================================================
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Type-safe error handling without exceptions.
|
|
34
|
+
*/
|
|
35
|
+
export type Result<T, E = Error> =
|
|
36
|
+
| { success: true; data: T }
|
|
37
|
+
| { success: false; error: E }
|
|
38
|
+
|
|
39
|
+
export const ok = <T>(data: T): Result<T, never> => ({
|
|
40
|
+
success: true,
|
|
41
|
+
data
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
export const err = <E>(error: E): Result<never, E> => ({
|
|
45
|
+
success: false,
|
|
46
|
+
error
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// OPTION TYPE (Nullable Handling)
|
|
51
|
+
// =============================================================================
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Explicit optional value handling.
|
|
55
|
+
*/
|
|
56
|
+
export type Option<T> = Some<T> | None
|
|
57
|
+
|
|
58
|
+
export type Some<T> = { type: 'some'; value: T }
|
|
59
|
+
export type None = { type: 'none' }
|
|
60
|
+
|
|
61
|
+
export const some = <T>(value: T): Some<T> => ({ type: 'some', value })
|
|
62
|
+
export const none: None = { type: 'none' }
|
|
63
|
+
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// DEEP UTILITIES
|
|
66
|
+
// =============================================================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Make all properties deeply readonly.
|
|
70
|
+
*/
|
|
71
|
+
export type DeepReadonly<T> = T extends (...args: any[]) => any
|
|
72
|
+
? T
|
|
73
|
+
: T extends object
|
|
74
|
+
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
|
|
75
|
+
: T
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Make all properties deeply optional.
|
|
79
|
+
*/
|
|
80
|
+
export type DeepPartial<T> = T extends object
|
|
81
|
+
? { [K in keyof T]?: DeepPartial<T[K]> }
|
|
82
|
+
: T
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Make all properties deeply required.
|
|
86
|
+
*/
|
|
87
|
+
export type DeepRequired<T> = T extends object
|
|
88
|
+
? { [K in keyof T]-?: DeepRequired<T[K]> }
|
|
89
|
+
: T
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Make all properties deeply mutable (remove readonly).
|
|
93
|
+
*/
|
|
94
|
+
export type DeepMutable<T> = T extends object
|
|
95
|
+
? { -readonly [K in keyof T]: DeepMutable<T[K]> }
|
|
96
|
+
: T
|
|
97
|
+
|
|
98
|
+
// =============================================================================
|
|
99
|
+
// OBJECT UTILITIES
|
|
100
|
+
// =============================================================================
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get keys of object where value matches type.
|
|
104
|
+
*/
|
|
105
|
+
export type KeysOfType<T, V> = {
|
|
106
|
+
[K in keyof T]: T[K] extends V ? K : never
|
|
107
|
+
}[keyof T]
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Pick properties by value type.
|
|
111
|
+
*/
|
|
112
|
+
export type PickByType<T, V> = Pick<T, KeysOfType<T, V>>
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Omit properties by value type.
|
|
116
|
+
*/
|
|
117
|
+
export type OmitByType<T, V> = Omit<T, KeysOfType<T, V>>
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Make specific keys optional.
|
|
121
|
+
*/
|
|
122
|
+
export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Make specific keys required.
|
|
126
|
+
*/
|
|
127
|
+
export type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Make specific keys readonly.
|
|
131
|
+
*/
|
|
132
|
+
export type ReadonlyBy<T, K extends keyof T> = Omit<T, K> & Readonly<Pick<T, K>>
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Merge two types (second overrides first).
|
|
136
|
+
*/
|
|
137
|
+
export type Merge<T, U> = Omit<T, keyof U> & U
|
|
138
|
+
|
|
139
|
+
// =============================================================================
|
|
140
|
+
// ARRAY UTILITIES
|
|
141
|
+
// =============================================================================
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get element type from array.
|
|
145
|
+
*/
|
|
146
|
+
export type ElementOf<T> = T extends (infer E)[] ? E : never
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Tuple of specific length.
|
|
150
|
+
*/
|
|
151
|
+
export type Tuple<T, N extends number> = N extends N
|
|
152
|
+
? number extends N
|
|
153
|
+
? T[]
|
|
154
|
+
: _TupleOf<T, N, []>
|
|
155
|
+
: never
|
|
156
|
+
|
|
157
|
+
type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N
|
|
158
|
+
? R
|
|
159
|
+
: _TupleOf<T, N, [T, ...R]>
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Non-empty array.
|
|
163
|
+
*/
|
|
164
|
+
export type NonEmptyArray<T> = [T, ...T[]]
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* At least N elements.
|
|
168
|
+
*/
|
|
169
|
+
export type AtLeast<T, N extends number> = [...Tuple<T, N>, ...T[]]
|
|
170
|
+
|
|
171
|
+
// =============================================================================
|
|
172
|
+
// FUNCTION UTILITIES
|
|
173
|
+
// =============================================================================
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get function arguments as tuple.
|
|
177
|
+
*/
|
|
178
|
+
export type Arguments<T> = T extends (...args: infer A) => any ? A : never
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Get first argument of function.
|
|
182
|
+
*/
|
|
183
|
+
export type FirstArgument<T> = T extends (first: infer F, ...args: any[]) => any
|
|
184
|
+
? F
|
|
185
|
+
: never
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Async version of function.
|
|
189
|
+
*/
|
|
190
|
+
export type AsyncFunction<T extends (...args: any[]) => any> = (
|
|
191
|
+
...args: Parameters<T>
|
|
192
|
+
) => Promise<Awaited<ReturnType<T>>>
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Promisify return type.
|
|
196
|
+
*/
|
|
197
|
+
export type Promisify<T> = T extends (...args: infer A) => infer R
|
|
198
|
+
? (...args: A) => Promise<Awaited<R>>
|
|
199
|
+
: never
|
|
200
|
+
|
|
201
|
+
// =============================================================================
|
|
202
|
+
// STRING UTILITIES
|
|
203
|
+
// =============================================================================
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Split string by delimiter.
|
|
207
|
+
*/
|
|
208
|
+
export type Split<S extends string, D extends string> =
|
|
209
|
+
S extends `${infer T}${D}${infer U}`
|
|
210
|
+
? [T, ...Split<U, D>]
|
|
211
|
+
: [S]
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Join tuple to string.
|
|
215
|
+
*/
|
|
216
|
+
export type Join<T extends string[], D extends string> =
|
|
217
|
+
T extends []
|
|
218
|
+
? ''
|
|
219
|
+
: T extends [infer F extends string]
|
|
220
|
+
? F
|
|
221
|
+
: T extends [infer F extends string, ...infer R extends string[]]
|
|
222
|
+
? `${F}${D}${Join<R, D>}`
|
|
223
|
+
: never
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Path to nested object.
|
|
227
|
+
*/
|
|
228
|
+
export type PathOf<T, K extends keyof T = keyof T> = K extends string
|
|
229
|
+
? T[K] extends object
|
|
230
|
+
? K | `${K}.${PathOf<T[K]>}`
|
|
231
|
+
: K
|
|
232
|
+
: never
|
|
233
|
+
|
|
234
|
+
// =============================================================================
|
|
235
|
+
// UNION UTILITIES
|
|
236
|
+
// =============================================================================
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Last element of union.
|
|
240
|
+
*/
|
|
241
|
+
export type UnionLast<T> = UnionToIntersection<
|
|
242
|
+
T extends any ? () => T : never
|
|
243
|
+
> extends () => infer R
|
|
244
|
+
? R
|
|
245
|
+
: never
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Union to intersection.
|
|
249
|
+
*/
|
|
250
|
+
export type UnionToIntersection<U> = (
|
|
251
|
+
U extends any ? (k: U) => void : never
|
|
252
|
+
) extends (k: infer I) => void
|
|
253
|
+
? I
|
|
254
|
+
: never
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Union to tuple.
|
|
258
|
+
*/
|
|
259
|
+
export type UnionToTuple<T, L = UnionLast<T>> = [T] extends [never]
|
|
260
|
+
? []
|
|
261
|
+
: [...UnionToTuple<Exclude<T, L>>, L]
|
|
262
|
+
|
|
263
|
+
// =============================================================================
|
|
264
|
+
// VALIDATION UTILITIES
|
|
265
|
+
// =============================================================================
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Assert type at compile time.
|
|
269
|
+
*/
|
|
270
|
+
export type AssertEqual<T, U> =
|
|
271
|
+
(<V>() => V extends T ? 1 : 2) extends (<V>() => V extends U ? 1 : 2)
|
|
272
|
+
? true
|
|
273
|
+
: false
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Ensure type is not never.
|
|
277
|
+
*/
|
|
278
|
+
export type IsNever<T> = [T] extends [never] ? true : false
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Ensure type is any.
|
|
282
|
+
*/
|
|
283
|
+
export type IsAny<T> = 0 extends 1 & T ? true : false
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Ensure type is unknown.
|
|
287
|
+
*/
|
|
288
|
+
export type IsUnknown<T> = IsAny<T> extends true
|
|
289
|
+
? false
|
|
290
|
+
: unknown extends T
|
|
291
|
+
? true
|
|
292
|
+
: false
|
|
293
|
+
|
|
294
|
+
// =============================================================================
|
|
295
|
+
// JSON UTILITIES
|
|
296
|
+
// =============================================================================
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* JSON-safe types.
|
|
300
|
+
*/
|
|
301
|
+
export type JsonPrimitive = string | number | boolean | null
|
|
302
|
+
export type JsonArray = JsonValue[]
|
|
303
|
+
export type JsonObject = { [key: string]: JsonValue }
|
|
304
|
+
export type JsonValue = JsonPrimitive | JsonArray | JsonObject
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Make type JSON-serializable.
|
|
308
|
+
*/
|
|
309
|
+
export type Jsonify<T> = T extends JsonPrimitive
|
|
310
|
+
? T
|
|
311
|
+
: T extends undefined | ((...args: any[]) => any) | symbol
|
|
312
|
+
? never
|
|
313
|
+
: T extends { toJSON(): infer R }
|
|
314
|
+
? R
|
|
315
|
+
: T extends object
|
|
316
|
+
? { [K in keyof T]: Jsonify<T[K]> }
|
|
317
|
+
: never
|
|
318
|
+
|
|
319
|
+
// =============================================================================
|
|
320
|
+
// EXHAUSTIVE CHECK
|
|
321
|
+
// =============================================================================
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Ensure all cases are handled in switch/if.
|
|
325
|
+
*/
|
|
326
|
+
export function assertNever(value: never, message?: string): never {
|
|
327
|
+
throw new Error(message ?? `Unexpected value: ${value}`)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Exhaustive check without throwing.
|
|
332
|
+
*/
|
|
333
|
+
export function exhaustiveCheck(_value: never): void {
|
|
334
|
+
// This function should never be called
|
|
335
|
+
}
|