Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
---
name: record-string-unknown-pattern
description: TypeScript patterns from Senior to Principal/Staff level
type: reference
---

# TypeScript Patterns: Senior to Principal/Staff Level

## Senior Pattern: `T extends Record<string, unknown>`

Use for generic functions accepting dictionary-like objects.

### Why This Pattern

| Pattern | Level | Why |
|:---|:---|:---|
| `T extends any` | Junior | No constraint |
| `T extends object` | Intermediate | Too broad |
| `T extends Record<string, any>` | Intermediate | Unsafe values |
| **`T extends Record<string, unknown>`** | **Senior** | Safe + explicit |

### Key Points

1. **`unknown` vs `any`**: Forces type narrowing before use
2. **`Record` vs `object`**: Explicitly dictionary-like (not arrays/functions)
3. **Interface Gotcha**: Interfaces lack implicit index signatures

```typescript
interface UserInterface { name: string }
type UserType = { name: string }

process<T extends Record<string, unknown>>(obj: T) {}
process(UserType) // ✅ Works
process(UserInterface) // ❌ Error
```

---

## Principal/Staff Pattern: Template Literal Types

Extract keys from template string at compile-time for type-safe data.

```typescript
type ExtractKeys<S extends string> =
S extends `${string}{${infer Key}}${infer Rest}`
? (Key extends `${infer RealKey}:${string}` ? RealKey : Key) | ExtractKeys<Rest>
: never;

const formatTemplate = <S extends string>(
template: S,
data: Record<ExtractKeys<S>, unknown>
): string => { ... }

// Usage:
formatTemplate("Hello {name}", { name: "Alice" }); // ✅ Works
formatTemplate("Hello {name}", { age: 30 }); // ❌ Error: missing 'name'
```

### Why This Matters

- **Compile-time validation**: Missing keys are caught at compile time
- **No runtime surprises**: API forces correct usage
- **Self-documenting**: Template string defines required keys

---

## Senior-Level Regex State Management

Global regex with `/g` flag is stateful. Always reset `lastIndex`:

```typescript
const REGEX = /\{(\w+)(?::(\w+))?\}/g;

const hasTemplatePlaceholders = (message: string): boolean => {
REGEX.lastIndex = 0; // Reset before each use
return REGEX.test(message);
};
```

**Without reset**: Second call might return `false` even when pattern exists.

---

## Summary of Levels

| Level | Technique | Benefit |
|:---|:---|:---|
| Junior | `any`, no constraints | Works, but unsafe |
| Intermediate | `object`, `Record<string, any>` | Shape correct |
| Senior | `Record<string, unknown>` | Type-safe |
| Principal/Staff | Template Literal Types | Compile-time key validation |
105 changes: 105 additions & 0 deletions .claude/agent-memory/typescript-expert/stack-capture-patterns.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
---
name: stack-capture-patterns
description: Senior to Expert level patterns for stack trace handling
type: reference
---

# Stack Capture Patterns: Senior to Expert Level

## Senior Pattern: String-Based Stack Filtering

Clean up stack traces by filtering internal frames.

```typescript
const STACK_FRAME_PATTERN = /^\s+at\s+/i;

const captureStack = (message: string): string => {
const stack = new Error().stack || '';

const lines = stack.split('\n');
const cleanedLines: string[] = [`Error: ${message}`];

// Find start index (skip "Error: message" line)
let startIndex = 0;
for (let i = 0; i < lines.length; i++) {
if (STACK_FRAME_PATTERN.test(lines[i])) {
startIndex = i;
break;
}
}

// Filter internal frames
for (let i = startIndex; i < lines.length; i++) {
const line = lines[i];
if (line.includes('node_modules')) continue;
if (line.includes('__vite')) continue;
cleanedLines.push(line);
}

return cleanedLines.join('\n');
};
```

### Key Senior Points

1. **DX Focus**: Hide `node_modules/@deessejs` and `__vite` to show user-relevant frames
2. **Environmental Awareness**: Document V8-specific nature of `Error.stack`
3. **Defensive Programming**: Fallback to `|| ''` when stack is undefined
4. **Maintainable**: Use constants for regex patterns

---

## Expert Pattern: `Error.captureStackTrace` (V8 Only)

Use V8's built-in mechanism for faster, cleaner stack capture.

```typescript
const captureStack = (message: string): string => {
// Check for V8 environment
if (typeof Error.captureStackTrace === 'function') {
const container: { stack: string } = { stack: '' };

// Tells V8 to capture stack, stopping at captureStack function
Error.captureStackTrace(container, captureStack);

const cleanedStack = `Error: ${message}\n` + container.stack
.split('\n')
.slice(1) // Remove captureStack frame
.filter(line =>
!line.includes('node_modules') &&
!line.includes('__vite')
)
.join('\n');

return cleanedStack;
}

// Fallback for non-V8 environments
return `Error: ${message}`;
};
```

### Why Expert Level

- **Performance**: Native V8 handling vs string manipulation
- **Cleaner output**: V8 controls frame inclusion precisely
- **Same filtering**: Still provides DX-focused output

---

## Summary: When to Use Which

| Level | Method | When |
|:---|:---|:---|
| Senior | String manipulation | Cross-environment compatibility |
| Expert | `Error.captureStackTrace` | V8-only, performance-critical |
| Always | Filter internal frames | End-user DX priority |

---

## Key Takeaways

1. **DX First**: Stack traces should point to user code, not library internals
2. **Document Boundaries**: `Error.stack` is V8-specific, document limitations
3. **Defensive**: Always handle `undefined` stack cases
4. **Expert Option**: Use native APIs when available for better performance
Loading
Loading