feat: enhanced the writing skills

This commit is contained in:
duthaho
2026-04-18 18:50:39 +07:00
parent 7fa9a48c6c
commit 09538078e7
136 changed files with 10175 additions and 7947 deletions
+62
View File
@@ -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) |
@@ -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
@@ -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
@@ -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 { /* ... */ }
}
```