typescript-effect
npx skills add https://github.com/bsamiee/parametric_forge --skill typescript-effect
Agent 安装分布
Skill 文档
[H1][TYPESCRIPT-EFFECT]
Dictum: Six pillars govern TypeScript generationâalgorithmic, parametric, polymorphic, functional, expressive, typed.
Generate TypeScript code adhering to Effect ecosystem patterns.
Pillars:
- Algorithmic â Derive values from frozen
Bconstant - Parametric â Expose tuning via factory parameters
- Polymorphic â Select implementation via dispatch tables
- Functional-Monadic â Chain via Effect/Option pipelines
- Expression-Centric â Ternaries, implicit returns, no blocks
- Strong-Typed â Branded types via
@effect/schema
File Structure:
// --- [TYPES] -----------------------------------------------------------------
// --- [SCHEMA] ----------------------------------------------------------------
// --- [CONSTANTS] -------------------------------------------------------------
// --- [PURE_FUNCTIONS] --------------------------------------------------------
// --- [DISPATCH_TABLES] -------------------------------------------------------
// --- [EFFECT_PIPELINE] -------------------------------------------------------
// --- [ENTRY_POINT] -----------------------------------------------------------
// --- [EXPORT] ----------------------------------------------------------------
[CRITICAL]:
- [NEVER]
anyâ use branded types. - [NEVER]
let/varâ useconstonly. - [NEVER]
if/elseâ use dispatch tables or ternaries. - [NEVER]
for/whileâ use.map,.filter, Effect. - [NEVER]
try/catchâ use Effect error channel. - [NEVER] Default exports â use named exports (except
*.config.ts).
[1][ALGORITHMIC]
Dictum: Derive values from base constant via formulaâzero hardcoded literals.
Single frozen B constant per file. ALL values derive from B properties.
const B = Object.freeze({
fontSize: 16,
ratio: 1.333,
} as const);
const derive = (step: number): number => B.fontSize * B.ratio ** step;
const scale = Object.freeze({
sm: derive(-1), // 12px = 16 * 1.333^-1
md: derive(0), // 16px = 16 * 1.333^0
lg: derive(1), // 21px = 16 * 1.333^1
} as const);
[IMPORTANT]:
- [ALWAYS] Define ONE
Bconstant withObject.freeze(). - [ALWAYS] Express derivations as inline calculationsâformula IS the code.
- [ALWAYS] Trace every value to
Bthrough visible arithmetic. - [NEVER] Numeric literals outside
Bconstant.
[2][PARAMETRIC]
Dictum: Expose tuning at call-site via factory parametersâzero buried controls.
Factory functions accept partial config; merge with B defaults.
const B = Object.freeze({
timeoutMs: 5000,
maxAttempts: 3,
} as const);
const createRetry = (overrides: Partial<typeof B> = {}) =>
Object.freeze({
config: { ...B, ...overrides },
execute: <T>(fn: () => Promise<T>): Promise<T> => fn(),
});
// Call-site tuning
const fast = createRetry({ timeoutMs: 1000 });
const resilient = createRetry({ maxAttempts: 5 });
[IMPORTANT]:
- [ALWAYS] Defaults in
B; overrides at call-site. - [ALWAYS] Factory returns frozen object.
- [NEVER] Hardcode tunable values in implementation.
[3][POLYMORPHIC]
Dictum: Select implementation via keyed dispatchâzero conditional branching.
Dispatch tables replace if/else/switch. Discriminated unions enable exhaustiveness.
import { Schema } from 'effect';
const Shape = Schema.Union(
Schema.Struct({ kind: Schema.Literal('circle'), radius: Schema.Number }),
Schema.Struct({ kind: Schema.Literal('rect'), width: Schema.Number, height: Schema.Number }),
);
type Shape = typeof Shape.Type;
const handlers = {
circle: (s: Extract<Shape, { kind: 'circle' }>) => Math.PI * s.radius ** 2,
rect: (s: Extract<Shape, { kind: 'rect' }>) => s.width * s.height,
} as const satisfies Record<Shape['kind'], (s: never) => number>;
const area = (shape: Shape): number => handlers[shape.kind](shape as never);
[IMPORTANT]:
- [ALWAYS] Route via
handlers[discriminant](data). - [ALWAYS] Enforce exhaustiveness with
satisfies Record<Discriminant, Handler>. - [NEVER]
if/elsefor type-based dispatch. - [NEVER]
switch/casestatements.
[4][FUNCTIONAL-MONADIC]
Dictum: Chain operations via typed channelsâEffect for async/failable, Option for nullable.
Effect pipelines replace try/catch. Option wraps nullable values.
import { Effect, Option, pipe } from 'effect';
class ValidationError {
readonly _tag = 'ValidationError';
constructor(readonly reason: string) {}
}
const processUser = (raw: { name?: string }) =>
pipe(
Option.fromNullable(raw.name),
Option.map((name) => name.trim().toUpperCase()),
Option.match({
onNone: () => Effect.fail(new ValidationError('Missing name')),
onSome: (name) => Effect.succeed({ name }),
}),
);
// Effect<{ name: string }, ValidationError, never>
[IMPORTANT]:
- [ALWAYS] Wrap nullable with
Option.fromNullable(). - [ALWAYS] Sequence via
pipe()andEffect.flatMap(). - [ALWAYS] Track outcomes in type parameters:
Effect<A, E, R>. - [NEVER]
try/catchorthrowin Effect code. - [NEVER] Null checks or optional chaining in logic.
[5][EXPRESSION-CENTRIC]
Dictum: Write code as value-producing expressionsâzero statement blocks.
Ternaries for conditionals. Implicit returns for arrows. Chain expressions.
// Expression: ternary + implicit return
const classify = (age: number): string =>
age < 18 ? 'minor' : age < 65 ? 'adult' : 'senior';
// Expression: chained transforms
const processUsers = (users: ReadonlyArray<{ name: string; age: number }>) =>
users
.filter((u) => u.age >= 18)
.map((u) => ({ ...u, name: u.name.toUpperCase() }))
.sort((a, b) => a.name.localeCompare(b.name));
[IMPORTANT]:
- [ALWAYS] Ternary
? :overif/else. - [ALWAYS] Arrow with implicit return:
x => x * 2. - [ALWAYS] Compose via
.map(),.filter(),pipe(). - [NEVER] Curly braces
{}in single-expression contexts. - [NEVER] Intermediate
letbindings.
[6][STRONG-TYPED]
Dictum: Brand domain primitives via @effect/schemaâzero raw primitives in domain logic.
Branded types enforce semantic boundaries. Schema validates at system edges.
import { Schema } from 'effect';
// Branded primitive
const UserId = Schema.String.pipe(Schema.brand('UserId'));
type UserId = typeof UserId.Type;
// Validated struct
const UserSchema = Schema.Struct({
id: UserId,
email: Schema.String.pipe(Schema.pattern(/@/)),
age: Schema.Number.pipe(Schema.positive()),
});
type User = typeof UserSchema.Type;
// Decode at boundary
const parseUser = Schema.decodeUnknownSync(UserSchema);
[IMPORTANT]:
- [ALWAYS] Brand domain primitives:
UserId,Email,IsoDate. - [ALWAYS] Validate at system boundaries (API input, external data).
- [ALWAYS] Derive type from schema:
typeof Schema.Type. - [NEVER]
anyor unbranded primitives in domain logic.
[7][VALIDATION]
Dictum: Gates prevent non-compliant code generation.
[VERIFY] Before completing any TypeScript generation:
- B Constant: Single frozen
Bwith all tunable values. - Derivation: All computed values trace to
Bvia visible arithmetic. - Factory:
createXpattern with partial config mergingB. - Dispatch: Handlers object with
satisfies Record<K, Handler>. - Effect: Async/failable operations use Effect pipelines.
- Option: Nullable values wrapped with
Option.fromNullable(). - Expression: No
if/elseblocks; ternaries and implicit returns. - Branded: Domain primitives use
Schema.brand(). - Sections: File uses canonical section separators.
- Exports: Named exports only (except
*.config.ts).
[CRITICAL] Violation detected â Refactor before completion.