mirror of
https://github.com/duthaho/claudekit.git
synced 2026-09-06 02:00:53 +03:00
feat: enhanced the writing skills
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
---
|
||||
name: languages
|
||||
description: >
|
||||
Use when working with Python, TypeScript, or JavaScript language-specific patterns — including type hints, generics, async/await, dataclasses, Pydantic, PEP 8, strict mode, tsconfig.json, Zod schemas, ESM/CJS, destructuring, optional chaining, or language idioms.
|
||||
---
|
||||
|
||||
# Languages
|
||||
|
||||
## When to Use
|
||||
|
||||
- Python files (.py) — type hints, async/await, dataclasses, Pydantic, context managers, PEP 8
|
||||
- TypeScript files (.ts, .tsx) — strict mode, generics, utility types, Zod, discriminated unions
|
||||
- JavaScript files (.js, .mjs, .cjs) — ES6+ patterns, ESM/CJS, ESLint, modern syntax
|
||||
- Language-specific idioms, package management (pip, pnpm), or migration between languages
|
||||
|
||||
## When NOT to Use
|
||||
|
||||
- Framework-specific patterns — use `backend-frameworks` or `frontend`
|
||||
- Testing — use `testing`
|
||||
- Database queries — use `databases`
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Language | Reference | Key features |
|
||||
|----------|-----------|-------------|
|
||||
| Python | `references/python.md` | Type hints, dataclasses, Pydantic, asyncio, context managers, PEP 8 |
|
||||
| TypeScript | `references/typescript.md` | Strict mode, generics, utility types, Zod, discriminated unions, satisfies |
|
||||
| JavaScript | `references/javascript.md` | ES6+, async/await, ESM/CJS, destructuring, private fields, structuredClone |
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use type hints on all public functions** (Python) / **enable strict mode** (TypeScript).
|
||||
2. **Prefer dataclasses or Pydantic for structured data** (Python) / **interfaces for object shapes** (TypeScript).
|
||||
3. **Use context managers for resource management** (Python).
|
||||
4. **Never use `any`** — use `unknown` instead (TypeScript).
|
||||
5. **Use `const` by default, `let` when needed, never `var`** (JavaScript).
|
||||
6. **Validate external data at boundaries** — Zod (TypeScript) or Pydantic (Python).
|
||||
7. **Handle all promise rejections** (JavaScript/TypeScript).
|
||||
8. **Follow PEP 8 / ESLint + Prettier** consistently.
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Mutable default arguments** (Python) — use `None` with default in function body.
|
||||
2. **Blocking calls inside async functions** (Python) — use `asyncio`-compatible libraries.
|
||||
3. **Overusing type assertions `as`** (TypeScript) — use type guards instead.
|
||||
4. **Implicit type coercion** (JavaScript) — always use `===` and `!==`.
|
||||
5. **Forgetting `await`** (all three languages).
|
||||
6. **Circular imports** (Python) / **circular dependencies** (TypeScript).
|
||||
7. **`this` binding in callbacks** (JavaScript) — use arrow functions.
|
||||
8. **Using enums instead of const objects** (TypeScript).
|
||||
|
||||
---
|
||||
|
||||
## Related Skills
|
||||
|
||||
- `backend-frameworks` — Framework-specific patterns
|
||||
- `testing` — Language-specific test frameworks
|
||||
- `error-handling` — Exception handling patterns
|
||||
@@ -1,247 +0,0 @@
|
||||
# Modern JavaScript Patterns Quick Reference
|
||||
|
||||
> ES2020+ patterns. All examples work in current Node.js (18+) and modern browsers.
|
||||
|
||||
## Destructuring Tricks
|
||||
|
||||
```javascript
|
||||
// Nested destructuring with rename and default
|
||||
const { data: { users: members = [] } = {} } = response;
|
||||
|
||||
// Array destructuring: skip elements
|
||||
const [first, , third] = [1, 2, 3];
|
||||
|
||||
// Swap variables
|
||||
[a, b] = [b, a];
|
||||
|
||||
// Rest in both arrays and objects
|
||||
const { id, ...rest } = user;
|
||||
const [head, ...tail] = items;
|
||||
|
||||
// Destructure function parameters
|
||||
function draw({ x = 0, y = 0, color = "black" } = {}) { /* ... */ }
|
||||
|
||||
// Dynamic property destructuring
|
||||
const key = "name";
|
||||
const { [key]: value } = { name: "Alice" }; // value = "Alice"
|
||||
|
||||
// Destructure from iterables
|
||||
const [a, b] = new Map([["a", 1], ["b", 2]]);
|
||||
```
|
||||
|
||||
## Optional Chaining (?.)
|
||||
|
||||
```javascript
|
||||
// Property access
|
||||
const city = user?.address?.city;
|
||||
|
||||
// Method call (only calls if method exists)
|
||||
const result = api?.getData?.();
|
||||
|
||||
// Bracket notation
|
||||
const val = obj?.["dynamic-key"];
|
||||
|
||||
// Array index
|
||||
const first = arr?.[0];
|
||||
|
||||
// Combine with nullish coalescing
|
||||
const name = user?.profile?.name ?? "Anonymous";
|
||||
|
||||
// Short-circuit: stops evaluating after first nullish
|
||||
const len = response?.data?.items?.length; // undefined if any is nullish
|
||||
```
|
||||
|
||||
## Nullish Coalescing (??) vs OR (||)
|
||||
|
||||
```javascript
|
||||
// ?? only triggers on null/undefined (NOT 0, "", false)
|
||||
0 ?? "fallback" // 0
|
||||
"" ?? "fallback" // ""
|
||||
null ?? "fallback" // "fallback"
|
||||
|
||||
// || triggers on any falsy value
|
||||
0 || "fallback" // "fallback"
|
||||
"" || "fallback" // "fallback"
|
||||
null || "fallback" // "fallback"
|
||||
|
||||
// Use ?? for values where 0/empty string are valid
|
||||
const port = config.port ?? 3000;
|
||||
const title = config.title ?? "Untitled";
|
||||
```
|
||||
|
||||
## Logical Assignment Operators
|
||||
|
||||
```javascript
|
||||
// ??= assigns only if current value is null/undefined
|
||||
user.name ??= "Anonymous";
|
||||
// Equivalent: user.name = user.name ?? "Anonymous"
|
||||
|
||||
// ||= assigns if current value is falsy
|
||||
opts.verbose ||= false;
|
||||
// Equivalent: opts.verbose = opts.verbose || false
|
||||
|
||||
// &&= assigns only if current value is truthy
|
||||
user.token &&= encrypt(user.token);
|
||||
// Equivalent: user.token = user.token && encrypt(user.token)
|
||||
```
|
||||
|
||||
## structuredClone (Deep Copy)
|
||||
|
||||
```javascript
|
||||
// Deep clone objects, arrays, Maps, Sets, Dates, RegExp, etc.
|
||||
const original = { date: new Date(), nested: { arr: [1, 2] } };
|
||||
const clone = structuredClone(original);
|
||||
clone.nested.arr.push(3); // original not affected
|
||||
|
||||
// Works with circular references
|
||||
const obj = { self: null };
|
||||
obj.self = obj;
|
||||
const copy = structuredClone(obj); // OK
|
||||
|
||||
// Does NOT clone: functions, DOM nodes, symbols, prototype chain
|
||||
// Throws on: functions, Error objects (in some engines)
|
||||
```
|
||||
|
||||
## Proxy
|
||||
|
||||
```javascript
|
||||
// Validation proxy
|
||||
const validated = new Proxy({}, {
|
||||
set(target, prop, value) {
|
||||
if (prop === "age" && (typeof value !== "number" || value < 0)) {
|
||||
throw new TypeError("Age must be a non-negative number");
|
||||
}
|
||||
target[prop] = value;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Read-only proxy
|
||||
function readonly(target) {
|
||||
return new Proxy(target, {
|
||||
set() { throw new Error("Read-only object"); },
|
||||
deleteProperty() { throw new Error("Read-only object"); }
|
||||
});
|
||||
}
|
||||
|
||||
// Default values proxy
|
||||
function withDefaults(target, defaults) {
|
||||
return new Proxy(target, {
|
||||
get(obj, prop) {
|
||||
return prop in obj ? obj[prop] : defaults[prop];
|
||||
}
|
||||
});
|
||||
}
|
||||
const config = withDefaults({}, { theme: "dark", lang: "en" });
|
||||
config.theme; // "dark"
|
||||
|
||||
// Logging / observation proxy
|
||||
function observable(target, onChange) {
|
||||
return new Proxy(target, {
|
||||
set(obj, prop, value) {
|
||||
const old = obj[prop];
|
||||
obj[prop] = value;
|
||||
onChange(prop, old, value);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Generators
|
||||
|
||||
```javascript
|
||||
// Basic generator
|
||||
function* range(start, end, step = 1) {
|
||||
for (let i = start; i < end; i += step) {
|
||||
yield i;
|
||||
}
|
||||
}
|
||||
for (const n of range(0, 10, 2)) { /* 0, 2, 4, 6, 8 */ }
|
||||
|
||||
// Infinite sequence
|
||||
function* ids() {
|
||||
let id = 0;
|
||||
while (true) yield id++;
|
||||
}
|
||||
const gen = ids();
|
||||
gen.next().value; // 0
|
||||
gen.next().value; // 1
|
||||
|
||||
// Delegate to another generator
|
||||
function* concat(...iterables) {
|
||||
for (const it of iterables) {
|
||||
yield* it;
|
||||
}
|
||||
}
|
||||
|
||||
// Two-way communication
|
||||
function* stateMachine() {
|
||||
let input;
|
||||
while (true) {
|
||||
input = yield `received: ${input}`;
|
||||
}
|
||||
}
|
||||
const sm = stateMachine();
|
||||
sm.next(); // { value: "received: undefined" }
|
||||
sm.next("hello"); // { value: "received: hello" }
|
||||
```
|
||||
|
||||
## Async Iterators
|
||||
|
||||
```javascript
|
||||
// for-await-of
|
||||
async function processStream(stream) {
|
||||
for await (const chunk of stream) {
|
||||
console.log(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
// Async generator
|
||||
async function* fetchPages(url) {
|
||||
let page = 1;
|
||||
while (true) {
|
||||
const res = await fetch(`${url}?page=${page}`);
|
||||
const data = await res.json();
|
||||
if (data.items.length === 0) return;
|
||||
yield data.items;
|
||||
page++;
|
||||
}
|
||||
}
|
||||
|
||||
for await (const items of fetchPages("/api/users")) {
|
||||
console.log(items);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Other Modern Patterns
|
||||
|
||||
```javascript
|
||||
// Object.groupBy (ES2024)
|
||||
const grouped = Object.groupBy(users, u => u.role);
|
||||
|
||||
// at() - negative indexing
|
||||
[1, 2, 3].at(-1); // 3
|
||||
|
||||
// Object.hasOwn (replaces hasOwnProperty)
|
||||
Object.hasOwn(obj, "key"); // true/false
|
||||
|
||||
// Error cause chaining
|
||||
throw new Error("DB failed", { cause: originalError });
|
||||
|
||||
// AbortSignal.timeout (built-in timeout)
|
||||
fetch(url, { signal: AbortSignal.timeout(5000) });
|
||||
|
||||
// using keyword (explicit resource management, ES2024+)
|
||||
{ using handle = openFile("data.txt"); } // auto-disposed at block exit
|
||||
```
|
||||
|
||||
## Promise Combinators
|
||||
|
||||
| Method | Settles when | Returns |
|
||||
|--------|-------------|---------|
|
||||
| `Promise.all(ps)` | All fulfill or one rejects | Array of values |
|
||||
| `Promise.allSettled(ps)` | All settle | Array of `{status, value/reason}` |
|
||||
| `Promise.race(ps)` | First settles | First value or rejection |
|
||||
| `Promise.any(ps)` | First fulfills | First value (AggregateError if all reject) |
|
||||
@@ -1,216 +0,0 @@
|
||||
# Python Type Hints Quick Reference
|
||||
|
||||
> Python 3.10+ syntax preferred. For 3.9, use `from __future__ import annotations`.
|
||||
|
||||
## Basic Types
|
||||
|
||||
| Type | Example | Notes |
|
||||
|------|---------|-------|
|
||||
| `int` | `x: int = 1` | |
|
||||
| `float` | `x: float = 1.0` | |
|
||||
| `str` | `x: str = "hi"` | |
|
||||
| `bool` | `x: bool = True` | |
|
||||
| `bytes` | `x: bytes = b"hi"` | |
|
||||
| `None` | `x: None = None` | Use as return type for side-effect functions |
|
||||
| `object` | `x: object` | Accepts anything, but no attribute access |
|
||||
| `Any` | `x: Any` | Escapes type checking entirely |
|
||||
|
||||
## Collection Types (3.10+)
|
||||
|
||||
| Type | Example | Notes |
|
||||
|------|---------|-------|
|
||||
| `list[int]` | `x: list[int] = [1, 2]` | Mutable sequence |
|
||||
| `tuple[int, str]` | `x: tuple[int, str]` | Fixed length |
|
||||
| `tuple[int, ...]` | `x: tuple[int, ...]` | Variable length |
|
||||
| `dict[str, int]` | `x: dict[str, int]` | |
|
||||
| `set[str]` | `x: set[str]` | |
|
||||
| `frozenset[str]` | `x: frozenset[str]` | |
|
||||
|
||||
## Union and Optional
|
||||
|
||||
```python
|
||||
# 3.10+ syntax
|
||||
def f(x: int | str) -> None: ...
|
||||
def g(x: int | None = None) -> None: ...
|
||||
|
||||
# Pre-3.10
|
||||
from typing import Union, Optional
|
||||
def f(x: Union[int, str]) -> None: ...
|
||||
def g(x: Optional[int] = None) -> None: ...
|
||||
```
|
||||
|
||||
## TypeAlias
|
||||
|
||||
```python
|
||||
from typing import TypeAlias
|
||||
|
||||
# Explicit alias (3.10+)
|
||||
Vector: TypeAlias = list[float]
|
||||
|
||||
# 3.12+ syntax
|
||||
type Vector = list[float]
|
||||
type Tree[T] = T | list["Tree[T]"] # recursive
|
||||
```
|
||||
|
||||
## Generics with TypeVar
|
||||
|
||||
```python
|
||||
from typing import TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
K = TypeVar("K", bound=str) # upper bound
|
||||
N = TypeVar("N", int, float) # constrained
|
||||
|
||||
def first(items: list[T]) -> T:
|
||||
return items[0]
|
||||
|
||||
# 3.12+ syntax (no TypeVar needed)
|
||||
def first[T](items: list[T]) -> T:
|
||||
return items[0]
|
||||
```
|
||||
|
||||
## ParamSpec and Concatenate
|
||||
|
||||
```python
|
||||
from typing import ParamSpec, Concatenate, Callable
|
||||
|
||||
P = ParamSpec("P")
|
||||
T = TypeVar("T")
|
||||
|
||||
# Preserve function signatures through decorators
|
||||
def logged(fn: Callable[P, T]) -> Callable[P, T]:
|
||||
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
||||
print(f"Calling {fn.__name__}")
|
||||
return fn(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
# Add a parameter to a function signature
|
||||
def with_user(
|
||||
fn: Callable[Concatenate[User, P], T]
|
||||
) -> Callable[P, T]:
|
||||
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
||||
return fn(get_current_user(), *args, **kwargs)
|
||||
return wrapper
|
||||
```
|
||||
|
||||
## Protocol (Structural Typing)
|
||||
|
||||
```python
|
||||
from typing import Protocol, runtime_checkable
|
||||
|
||||
class Renderable(Protocol):
|
||||
def render(self) -> str: ...
|
||||
|
||||
class Widget(Protocol):
|
||||
name: str
|
||||
def resize(self, width: int, height: int) -> None: ...
|
||||
|
||||
# Any class with matching methods satisfies the protocol
|
||||
class Button:
|
||||
def render(self) -> str:
|
||||
return "<button/>"
|
||||
|
||||
def draw(item: Renderable) -> None: # Button works here
|
||||
print(item.render())
|
||||
|
||||
# Runtime checking
|
||||
@runtime_checkable
|
||||
class Sized(Protocol):
|
||||
def __len__(self) -> int: ...
|
||||
|
||||
assert isinstance([1, 2], Sized) # True at runtime
|
||||
```
|
||||
|
||||
## @overload
|
||||
|
||||
```python
|
||||
from typing import overload
|
||||
|
||||
@overload
|
||||
def parse(data: str) -> dict[str, Any]: ...
|
||||
@overload
|
||||
def parse(data: bytes) -> list[int]: ...
|
||||
@overload
|
||||
def parse(data: str, raw: Literal[True]) -> str: ...
|
||||
|
||||
def parse(data: str | bytes, raw: bool = False) -> dict | list | str:
|
||||
"""Implementation handles all overloads."""
|
||||
...
|
||||
```
|
||||
|
||||
## TypeGuard and TypeIs
|
||||
|
||||
```python
|
||||
from typing import TypeGuard, TypeIs # TypeIs: 3.13+
|
||||
|
||||
# TypeGuard: narrows type in True branch only
|
||||
def is_str_list(val: list[object]) -> TypeGuard[list[str]]:
|
||||
return all(isinstance(x, str) for x in val)
|
||||
|
||||
# TypeIs: narrows in both True and False branches
|
||||
def is_int(val: int | str) -> TypeIs[int]:
|
||||
return isinstance(val, int)
|
||||
|
||||
def f(val: int | str) -> None:
|
||||
if is_int(val):
|
||||
reveal_type(val) # int
|
||||
else:
|
||||
reveal_type(val) # str (only with TypeIs)
|
||||
```
|
||||
|
||||
## Literal and Final
|
||||
|
||||
```python
|
||||
from typing import Literal, Final
|
||||
|
||||
def set_mode(mode: Literal["read", "write", "append"]) -> None: ...
|
||||
|
||||
MAX_SIZE: Final = 100 # Cannot be reassigned
|
||||
PREFIX: Final[str] = "app_" # With explicit type
|
||||
```
|
||||
|
||||
## Callable
|
||||
|
||||
| Signature | Meaning |
|
||||
|-----------|---------|
|
||||
| `Callable[[int, str], bool]` | Function taking int and str, returning bool |
|
||||
| `Callable[..., bool]` | Any args, returning bool |
|
||||
| `Callable[P, T]` | Generic (use with ParamSpec) |
|
||||
|
||||
## TypedDict
|
||||
|
||||
```python
|
||||
from typing import TypedDict, NotRequired, Required
|
||||
|
||||
class Config(TypedDict):
|
||||
name: str
|
||||
debug: NotRequired[bool] # optional key
|
||||
|
||||
class PartialConfig(TypedDict, total=False):
|
||||
name: Required[str] # required even though total=False
|
||||
debug: bool # optional
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
| Pattern | Type Hint |
|
||||
|---------|-----------|
|
||||
| JSON value | `dict[str, Any]` or custom TypedDict |
|
||||
| Decorator preserving sig | `Callable[P, T] -> Callable[P, T]` |
|
||||
| Context manager | `AbstractContextManager[T]` |
|
||||
| Async context manager | `AbstractAsyncContextManager[T]` |
|
||||
| Generator | `Generator[YieldType, SendType, ReturnType]` |
|
||||
| Async generator | `AsyncGenerator[YieldType, SendType]` |
|
||||
| Class method returning self | `-> Self` (3.11+, `from typing import Self`) |
|
||||
| Numeric tower | `int | float` (avoid `numbers.Number`) |
|
||||
|
||||
## Type Narrowing Cheat Sheet
|
||||
|
||||
| Technique | Example |
|
||||
|-----------|---------|
|
||||
| `isinstance` | `if isinstance(x, str):` |
|
||||
| `is None` / `is not None` | `if x is not None:` |
|
||||
| `TypeGuard` / `TypeIs` | Custom narrowing functions |
|
||||
| `assert` | `assert isinstance(x, str)` |
|
||||
| `Literal` checks | `if x == "read":` |
|
||||
| `hasattr` | `if hasattr(x, "render"):` (limited) |
|
||||
+7
-10
@@ -1,8 +1,5 @@
|
||||
---
|
||||
name: javascript
|
||||
description: >
|
||||
Trigger this skill whenever working with JavaScript files (.js, .mjs, .cjs), writing Node.js applications without TypeScript, or using ES6+ patterns like destructuring, async/await, optional chaining, and modules. Activate for browser scripting, vanilla JS projects, or when the user asks about JavaScript-specific idioms, ESLint configuration, or modern syntax. Also use when dealing with package.json scripts, CommonJS vs ESM, or JavaScript class patterns.
|
||||
---
|
||||
# Languages — JavaScript Patterns
|
||||
|
||||
|
||||
# JavaScript
|
||||
|
||||
@@ -14,7 +11,7 @@ description: >
|
||||
|
||||
## When NOT to Use
|
||||
|
||||
- TypeScript projects -- use the `languages/typescript` skill instead, which covers typed JavaScript patterns
|
||||
- TypeScript projects -- use the `typescript` skill instead, which covers typed JavaScript patterns
|
||||
- Python-only projects with no JavaScript components
|
||||
|
||||
---
|
||||
@@ -718,7 +715,7 @@ performance.clearMeasures();
|
||||
|
||||
## Related Skills
|
||||
|
||||
- `languages/typescript` -- TypeScript for typed JavaScript development
|
||||
- `frameworks/react` -- React component patterns
|
||||
- `frameworks/nextjs` -- Next.js full-stack framework
|
||||
- `testing/vitest` -- JavaScript/TypeScript testing with Vitest
|
||||
- `typescript` -- TypeScript for typed JavaScript development
|
||||
- `react` -- React component patterns
|
||||
- `nextjs` -- Next.js full-stack framework
|
||||
- `vitest` -- JavaScript/TypeScript testing with Vitest
|
||||
+7
-10
@@ -1,8 +1,5 @@
|
||||
---
|
||||
name: python
|
||||
description: >
|
||||
Trigger this skill whenever working with Python files (.py), writing Python scripts or applications, or using Python frameworks like Django, FastAPI, or Flask. Activate for any Python-specific patterns including type hints, async/await with asyncio, dataclasses, Pydantic models, context managers, virtual environments, or PEP 8 style questions. Also use when the user references Python package management, pip, or pyproject.toml.
|
||||
---
|
||||
# Languages — Python Patterns
|
||||
|
||||
|
||||
# Python
|
||||
|
||||
@@ -693,8 +690,8 @@ with suppress(FileNotFoundError):
|
||||
|
||||
## Related Skills
|
||||
|
||||
- `languages/typescript` -- TypeScript language patterns for polyglot projects
|
||||
- `frameworks/fastapi` -- FastAPI web framework built on Python
|
||||
- `frameworks/django` -- Django web framework for Python
|
||||
- `testing/pytest` -- Python testing with pytest
|
||||
- `patterns/error-handling` -- Python error handling and exception hierarchies
|
||||
- `typescript` -- TypeScript language patterns for polyglot projects
|
||||
- `fastapi` -- FastAPI web framework built on Python
|
||||
- `django` -- Django web framework for Python
|
||||
- `pytest` -- Python testing with pytest
|
||||
- `error-handling` -- Python error handling and exception hierarchies
|
||||
+9
-12
@@ -1,8 +1,5 @@
|
||||
---
|
||||
name: typescript
|
||||
description: >
|
||||
Trigger this skill whenever working with TypeScript files (.ts, .tsx), configuring tsconfig.json, or using TypeScript-specific features like strict typing, generics, utility types, or type guards. Activate for any TypeScript project setup, type definition authoring, Zod schema validation, or discriminated union patterns. Also use when the user asks about avoiding `any`, enabling strict mode, or migrating JavaScript to TypeScript.
|
||||
---
|
||||
# Languages — TypeScript Patterns
|
||||
|
||||
|
||||
# TypeScript
|
||||
|
||||
@@ -684,10 +681,10 @@ function getLabel(role: "admin" | "user" | "guest"): string {
|
||||
|
||||
## Related Skills
|
||||
|
||||
- `languages/javascript` -- JavaScript patterns for JS interop and migration
|
||||
- `languages/python` -- Python language patterns for polyglot projects
|
||||
- `frameworks/react` -- React component patterns with TypeScript
|
||||
- `frameworks/nextjs` -- Next.js framework with TypeScript support
|
||||
- `testing/vitest` -- TypeScript testing with Vitest
|
||||
- `patterns/error-handling` -- TypeScript error handling patterns
|
||||
- `patterns/state-management` -- State management with TypeScript types
|
||||
- `javascript` -- JavaScript patterns for JS interop and migration
|
||||
- `python` -- Python language patterns for polyglot projects
|
||||
- `react` -- React component patterns with TypeScript
|
||||
- `nextjs` -- Next.js framework with TypeScript support
|
||||
- `vitest` -- TypeScript testing with Vitest
|
||||
- `error-handling` -- TypeScript error handling patterns
|
||||
- `state-management` -- State management with TypeScript types
|
||||
@@ -1,249 +0,0 @@
|
||||
# TypeScript Advanced Types Quick Reference
|
||||
|
||||
## Discriminated Unions
|
||||
|
||||
```typescript
|
||||
// Tag each variant with a literal type field
|
||||
type Shape =
|
||||
| { kind: "circle"; radius: number }
|
||||
| { kind: "rect"; width: number; height: number }
|
||||
| { kind: "triangle"; base: number; height: number };
|
||||
|
||||
function area(s: Shape): number {
|
||||
switch (s.kind) {
|
||||
case "circle": return Math.PI * s.radius ** 2;
|
||||
case "rect": return s.width * s.height;
|
||||
case "triangle": return (s.base * s.height) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Exhaustiveness check helper
|
||||
function assertNever(x: never): never {
|
||||
throw new Error(`Unexpected value: ${x}`);
|
||||
}
|
||||
```
|
||||
|
||||
## Branded Types
|
||||
|
||||
```typescript
|
||||
// Prevent mixing structurally identical types
|
||||
type Brand<T, B extends string> = T & { readonly __brand: B };
|
||||
|
||||
type UserId = Brand<string, "UserId">;
|
||||
type OrderId = Brand<string, "OrderId">;
|
||||
|
||||
function getUser(id: UserId) { /* ... */ }
|
||||
|
||||
const userId = "abc" as UserId;
|
||||
const orderId = "abc" as OrderId;
|
||||
|
||||
getUser(userId); // OK
|
||||
getUser(orderId); // Error: OrderId not assignable to UserId
|
||||
|
||||
// Validation-based branding
|
||||
type Email = Brand<string, "Email">;
|
||||
function parseEmail(input: string): Email {
|
||||
if (!input.includes("@")) throw new Error("Invalid email");
|
||||
return input as Email;
|
||||
}
|
||||
```
|
||||
|
||||
## Template Literal Types
|
||||
|
||||
```typescript
|
||||
// Build string types from unions
|
||||
type Method = "get" | "post" | "put" | "delete";
|
||||
type Route = "/users" | "/orders";
|
||||
type Endpoint = `${Uppercase<Method>} ${Route}`;
|
||||
// "GET /users" | "GET /orders" | "POST /users" | ...
|
||||
|
||||
// Event handler pattern
|
||||
type EventName = "click" | "focus" | "blur";
|
||||
type Handler = `on${Capitalize<EventName>}`;
|
||||
// "onClick" | "onFocus" | "onBlur"
|
||||
|
||||
// Extract parts from string types
|
||||
type ExtractParam<T extends string> =
|
||||
T extends `${string}:${infer Param}/${infer Rest}`
|
||||
? Param | ExtractParam<Rest>
|
||||
: T extends `${string}:${infer Param}`
|
||||
? Param
|
||||
: never;
|
||||
|
||||
type Params = ExtractParam<"/users/:id/posts/:postId">;
|
||||
// "id" | "postId"
|
||||
```
|
||||
|
||||
## Conditional Types
|
||||
|
||||
```typescript
|
||||
// Basic conditional
|
||||
type IsString<T> = T extends string ? true : false;
|
||||
|
||||
// Distributive over unions (when T is naked type parameter)
|
||||
type ToArray<T> = T extends unknown ? T[] : never;
|
||||
type Result = ToArray<string | number>; // string[] | number[]
|
||||
|
||||
// Prevent distribution with tuple wrapping
|
||||
type ToArrayNonDist<T> = [T] extends [unknown] ? T[] : never;
|
||||
type Result2 = ToArrayNonDist<string | number>; // (string | number)[]
|
||||
|
||||
// infer keyword
|
||||
type ReturnOf<T> = T extends (...args: any[]) => infer R ? R : never;
|
||||
type Unpacked<T> = T extends Promise<infer U> ? U :
|
||||
T extends Array<infer U> ? U : T;
|
||||
|
||||
// infer with constraints (TS 4.7+)
|
||||
type FirstString<T> =
|
||||
T extends [infer S extends string, ...unknown[]] ? S : never;
|
||||
```
|
||||
|
||||
## Mapped Types
|
||||
|
||||
```typescript
|
||||
// Transform all properties
|
||||
type Readonly<T> = { readonly [K in keyof T]: T[K] };
|
||||
type Optional<T> = { [K in keyof T]?: T[K] };
|
||||
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
|
||||
type Required<T> = { [K in keyof T]-?: T[K] };
|
||||
|
||||
// Map to new value types
|
||||
type Getters<T> = {
|
||||
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
|
||||
};
|
||||
|
||||
interface Person { name: string; age: number }
|
||||
type PersonGetters = Getters<Person>;
|
||||
// { getName: () => string; getAge: () => number }
|
||||
```
|
||||
|
||||
## Key Remapping (via `as`)
|
||||
|
||||
```typescript
|
||||
// Filter keys
|
||||
type OnlyStrings<T> = {
|
||||
[K in keyof T as T[K] extends string ? K : never]: T[K];
|
||||
};
|
||||
|
||||
// Rename keys
|
||||
type Prefixed<T, P extends string> = {
|
||||
[K in keyof T as `${P}${Capitalize<string & K>}`]: T[K];
|
||||
};
|
||||
|
||||
// Remove specific keys
|
||||
type RemoveKind<T> = {
|
||||
[K in keyof T as Exclude<K, "kind">]: T[K];
|
||||
};
|
||||
|
||||
// Build from union
|
||||
type EventMap<T extends string> = {
|
||||
[K in T as `on${Capitalize<K>}`]: (event: K) => void;
|
||||
};
|
||||
type Handlers = EventMap<"click" | "scroll">;
|
||||
// { onClick: (event: "click") => void; onScroll: (event: "scroll") => void }
|
||||
```
|
||||
|
||||
## Recursive Types
|
||||
|
||||
```typescript
|
||||
// JSON type
|
||||
type Json =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| Json[]
|
||||
| { [key: string]: Json };
|
||||
|
||||
// Deep readonly
|
||||
type DeepReadonly<T> = T extends Function
|
||||
? T
|
||||
: T extends object
|
||||
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
|
||||
: T;
|
||||
|
||||
// Deep partial
|
||||
type DeepPartial<T> = T extends object
|
||||
? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||
: T;
|
||||
|
||||
// Flatten nested object paths
|
||||
type Paths<T, Prefix extends string = ""> = T extends object
|
||||
? {
|
||||
[K in keyof T & string]: T[K] extends object
|
||||
? Paths<T[K], `${Prefix}${K}.`>
|
||||
: `${Prefix}${K}`;
|
||||
}[keyof T & string]
|
||||
: never;
|
||||
|
||||
type P = Paths<{ a: { b: number; c: { d: string } } }>;
|
||||
// "a.b" | "a.c.d"
|
||||
```
|
||||
|
||||
## Utility Types Cheat Sheet
|
||||
|
||||
| Utility | Effect |
|
||||
|---------|--------|
|
||||
| `Partial<T>` | All properties optional |
|
||||
| `Required<T>` | All properties required |
|
||||
| `Readonly<T>` | All properties readonly |
|
||||
| `Record<K, V>` | Object with keys K and values V |
|
||||
| `Pick<T, K>` | Subset of properties |
|
||||
| `Omit<T, K>` | All except listed properties |
|
||||
| `Exclude<U, E>` | Remove members from union |
|
||||
| `Extract<U, E>` | Keep matching members from union |
|
||||
| `NonNullable<T>` | Remove null and undefined |
|
||||
| `ReturnType<F>` | Return type of function |
|
||||
| `Parameters<F>` | Tuple of parameter types |
|
||||
| `ConstructorParameters<C>` | Constructor parameter types |
|
||||
| `InstanceType<C>` | Instance type of constructor |
|
||||
| `Awaited<T>` | Unwrap Promise (deeply) |
|
||||
| `NoInfer<T>` | Prevent inference from this position (5.4+) |
|
||||
|
||||
## Satisfies Operator (4.9+)
|
||||
|
||||
```typescript
|
||||
// Validate type without widening
|
||||
const palette = {
|
||||
red: "#ff0000",
|
||||
green: [0, 255, 0],
|
||||
} satisfies Record<string, string | number[]>;
|
||||
|
||||
palette.red.toUpperCase(); // OK - knows it's string
|
||||
palette.green.map(x => x); // OK - knows it's number[]
|
||||
```
|
||||
|
||||
## const Type Parameters (5.0+)
|
||||
|
||||
```typescript
|
||||
// Infer narrow literal types from arguments
|
||||
function routes<const T extends readonly string[]>(paths: T): T {
|
||||
return paths;
|
||||
}
|
||||
|
||||
const r = routes(["/home", "/about"]);
|
||||
// Type: readonly ["/home", "/about"] (not string[])
|
||||
```
|
||||
|
||||
## Pattern: Type-Safe Event Emitter
|
||||
|
||||
```typescript
|
||||
type EventMap = {
|
||||
login: { userId: string };
|
||||
logout: undefined;
|
||||
error: { code: number; message: string };
|
||||
};
|
||||
|
||||
class Emitter<E extends Record<string, unknown>> {
|
||||
on<K extends keyof E>(
|
||||
event: K,
|
||||
handler: E[K] extends undefined
|
||||
? () => void
|
||||
: (payload: E[K]) => void
|
||||
): void { /* ... */ }
|
||||
|
||||
emit<K extends keyof E>(
|
||||
...args: E[K] extends undefined ? [K] : [K, E[K]]
|
||||
): void { /* ... */ }
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user