wrdn-effect-value-inferred-types
GitHub自动将手动定义的TypeScript对象类型替换为由运行时工厂函数推断的类型。通过查找重复的类型定义,将其重构为ReturnType<typeof factory>,防止类型与实现脱节,同时保留稳定的导出名称供消费者使用。
触发场景
安装
npx skills add UsefulSoftwareCo/executor --skill wrdn-effect-value-inferred-types -g -y
SKILL.md
Frontmatter
{
"name": "wrdn-effect-value-inferred-types",
"description": "Replace duplicated object API types with types inferred from the runtime value or factory that owns the shape. Use when lint or review flags an interface\/type alias that mirrors a returned object such as a plugin extension, client surface, route map, or handler table.",
"allowed-tools": "Read Grep Glob Bash"
}
You fix one pattern: a TypeScript object type manually mirrors a runtime object that already owns the shape.
Prefer value-first APIs. Build the object in a named factory, then export type X = ReturnType<typeof makeX>. Consumers keep importing the stable type name, but the type cannot drift from the implementation.
Trace before changing
- Find the source value. Look for an object returned from a named factory,
extension: (...) => ({ ... }), a client object, route map, or handler table. - Find the duplicate type. A nearby
interface Xortype X = { ... }repeats the object methods/properties. - Check whether the value is the source of truth. If the interface is a contract with multiple implementations, keep the interface.
- Preserve the exported type name. Replace its definition with
ReturnType<typeof makeX>and update callers only if needed. - Use
satisfiesonly at boundaries. Do not make the implementation satisfy a duplicate shape that could drift.
Fix shape
const makePluginExtension = (ctx: PluginCtx<Store>) => {
const addSource = ...
const removeSource = ...
return {
addSource,
removeSource,
};
};
export type PluginExtension = ReturnType<typeof makePluginExtension>;
For factories that need options:
const makePluginExtension =
(options: PluginOptions) =>
(ctx: PluginCtx<Store>) => ({
addSource: ...,
});
export type PluginExtension = ReturnType<ReturnType<typeof makePluginExtension>>;
Bad
export interface McpPluginExtension {
readonly addSource: (config: McpSourceConfig) => Effect.Effect<AddResult, Failure>;
readonly removeSource: (namespace: string, scope: string) => Effect.Effect<void, Failure>;
}
extension: (ctx) => {
return {
addSource,
removeSource,
} satisfies McpPluginExtension;
};
Good
const makeMcpPluginExtension = (ctx: PluginCtx<McpStore>) => {
return {
addSource,
removeSource,
};
};
export type McpPluginExtension = ReturnType<typeof makeMcpPluginExtension>;
extension: makeMcpPluginExtension;
What not to report
- Service/dependency interfaces with multiple implementations.
- Public config input types that are intentionally a stable authored API.
- Branded IDs, discriminated unions, or small aliases that do not mirror one object value.
- Test fakes typed against an existing exported contract.
- Schema-owned data shapes; use
wrdn-effect-schema-inferred-typesfor those.
Output requirements
When reviewing, report:
- File and line of the duplicate object type or
satisfiesusage. - Value/factory that owns the shape.
- Why the manual type can drift.
- Fix: the exact
ReturnTypealias to introduce.
When editing, name the factory after the exported type, e.g. makeMcpPluginExtension for McpPluginExtension.
版本历史
- fd4fb02 当前 2026-07-05 10:55


