一键导入
typescript-guidelines
TypeScript-specific conventions — type narrowing, optional chaining, type safety. Applied automatically — not user-invocable.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
TypeScript-specific conventions — type narrowing, optional chaining, type safety. Applied automatically — not user-invocable.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Native batching framework for destination transformations. Extend BatchDestination to implement per-event transforms with automatic grouping, chunking, and response formatting.
Create the transformation logic for a new VDM V2 object-based destination. Implements record dispatch by object type and action, with batching and optional event-stream support.
Code design conventions — handler maps, dependency management, function extraction. Applied automatically — not user-invocable.
Conventions to follow when writing or modifying tests in this repo. Applied automatically — not user-invocable.
Create the transformation logic for a new VDM Next audience destination. Implements record processing, identifier hashing, batching, and API request building for audience-based integrations.
Generate detailed integration documentation for a rudder-transformer destination. Use when asked to create docs, README, or documentation for a destination integration.
| name | typescript-guidelines |
| description | TypeScript-specific conventions — type narrowing, optional chaining, type safety. Applied automatically — not user-invocable. |
Follow these conventions when writing TypeScript code.
Inside a type-specific handler or after narrowing, don't use ?. on properties that the type guarantees exist. It adds noise and obscures which properties are genuinely optional.
// Good — inside the "order" handler, lineItems is guaranteed
order: {
process: (event) => {
event.lineItems.forEach((item) => validateItem(item));
},
},
// Bad — unnecessary defensive chaining
order: {
process: (event) => {
event.lineItems?.forEach((item) => validateItem(item));
},
},
When a function returns success/failure outcomes, use a union type discriminated on a literal field — not a single type with optional fields.
// Good
type Result = { valid: true; recordFields: string[] } | { valid: false; errors: string[] };
// Bad
type Result = { valid: boolean; errors?: string[]; recordFields?: string[] };
Place type assertions as close as possible to where the value's shape is determined. This applies at two levels: wrapper functions should narrow their return type so callers never cast, and within a function, cast individual values at the point of production rather than on an aggregate after collection.
// Good — wrapper narrows; callers are type-safe
export async function sandboxedEvaluate(
template: string,
chunks: unknown[][],
): Promise<Record<string, unknown>[]> {
const result = await runner.execute<EvaluateResult>(key, expr);
return result.bodies; // typed Record<string, unknown>[] inside EvaluateResult
}
const bodies = await sandboxedEvaluate(template, chunks);
return chunks.map((chunk, i) => ({ body: bodies[i], jobIds: chunk.jobIds }));
// Bad — wrapper returns unknown[]; every caller casts
export async function sandboxedEvaluate(template: string, chunks: unknown[][]): Promise<unknown[]> {
const result = await runner.execute<{ bodies: unknown[] }>(key, expr);
return result.bodies;
}
const bodies = await sandboxedEvaluate(template, chunks);
return chunks.map((chunk, i) => ({
body: bodies[i] as Record<string, unknown>, // cast leaks into call site
jobIds: chunk.jobIds,
}));
Within a function, cast each value where it originates — not after aggregating into an array or object.
// Good — cast at the individual call site where the shape is known
const bodies = await Promise.all(
chunks.map(
(records) =>
evaluateTemplate(template, { records, connection }) as Promise<Record<string, unknown>>,
),
);
// Bad — cast on the collected aggregate
const bodies = (await Promise.all(
chunks.map((records) => evaluateTemplate(template, { records, connection })),
)) as Record<string, unknown>[];
unknown Over any for Generic ContainersUse unknown instead of any for Map, Promise, or collection types where the container doesn't need to know the value's shape. Callers can narrow with as T at the point of use.
// Good
private pendingCreations = new Map<string, Promise<unknown>>();
private cache = new Map<string, unknown>();
// Bad
private pendingCreations = new Map<string, Promise<any>>();
private cache = new Map<string, any>();
.finally() for Shared Cleanup in Promise ChainsWhen .then() and .catch() both need the same cleanup, move it to .finally() and keep only the success-path logic in .then().
// Good — cleanup in one place
pending = this.createEntry()
.then((entry) => {
this.cache.set(cacheKey, entry);
return entry;
})
.finally(() => {
this.pendingCreations.delete(cacheKey);
});
// Bad — duplicated cleanup
pending = this.createEntry()
.then((entry) => {
this.pendingCreations.delete(cacheKey);
this.cache.set(cacheKey, entry);
return entry;
})
.catch((err) => {
this.pendingCreations.delete(cacheKey);
throw err;
});