funkcia
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFunkcia Adoption
采用Funkcia
Migrate existing error handling and validation into explicit, typed, chainable flows using Funkcia.
将现有的错误处理和验证迁移为使用Funkcia的显式、类型化、可链式调用的流程。
Workflow
工作流程
- Start at boundaries, not internals.
- Migrate I/O edges first: API handlers, DB repositories, queue consumers, file readers.
- Keep module internals stable until boundary contracts return /
Option.Result
- Classify failure shape before coding.
- Use /
Optionfor expected absence without an error payload.OptionAsync - Use /
Resultfor expected failure with explicit error semantics.ResultAsync
- Use
- Define domain errors with before refactoring call chains.
TaggedError- Model application failures (auth, validation, not-found, rate limit, external dependency).
- Preserve causes when wrapping infrastructure failures.
- Transform imperative control flow.
- Replace with
try/catchorResult.try.ResultAsync.try - Replace null/falsy branching with /
fromNullable.fromFalsy - Prefer generator style for multi-step flows; use ,
map,andThen,filter,orfor focused one-step transforms.match
- Replace
- Resolve once at the boundary.
- Use in handlers/controllers to map outcomes to transport responses.
match - For tagged error unions (), prefer
_tagto enforce full case handling.exhaustive(error, { ... }) - Avoid in business logic.
unwrap
- Use
- Verify behavior and type contracts.
- Add runtime + tests.
expectTypeOf - Run repository checks before completion.
- Add runtime +
- 从边界开始,而非内部。
- 优先迁移I/O边界:API处理器、数据库仓库、队列消费者、文件读取器。
- 在边界契约返回/
Option之前,保持模块内部稳定。Result
- 编码前先分类失败形态。
- 当预期无错误负载的缺失场景时,使用/
Option。OptionAsync - 当预期有明确错误语义的失败场景时,使用/
Result。ResultAsync
- 当预期无错误负载的缺失场景时,使用
- 在重构调用链之前,使用定义领域错误。
TaggedError- 为应用层失败建模(认证、验证、未找到、速率限制、外部依赖)。
- 包装基础设施层失败时保留根因。
- 转换命令式控制流。
- 使用或
Result.try替代ResultAsync.try。try/catch - 使用/
fromNullable替代null/假值分支判断。fromFalsy - 多步骤流程优先使用生成器风格;单步骤转换优先使用、
map、andThen、filter、or。match
- 使用
- 在边界处一次性解析结果。
- 在处理器/控制器中使用将结果映射为传输层响应。
match - 对于带的标签化错误联合类型,优先使用
_tag来强制覆盖所有场景。exhaustive(error, { ... }) - 业务逻辑中避免使用。
unwrap
- 在处理器/控制器中使用
- 验证行为与类型契约。
- 添加运行时测试 + 类型测试。
expectTypeOf - 完成前运行仓库检查。
- 添加运行时测试 +
Migration Strategy
迁移策略
- Migrate incrementally by vertical slices (feature or module), not by type across the whole codebase.
- Keep adapters during migration when legacy callers still expect nullable or throwing APIs.
- Preserve behavior first, then improve ergonomics.
- Recommend wrapping shared dependencies (database clients, API SDKs, queues) with and mapping each dependency to pre-defined resource error types before wiring business flows.
ResultAsync.resource
- 按垂直切片(功能或模块)逐步迁移,而非跨整个代码库按类型迁移。
- 迁移期间保留适配器,以兼容仍期望可空或抛出异常API的遗留调用方。
- 先保留原有行为,再优化易用性。
- 建议使用包装共享依赖(数据库客户端、API SDK、队列),并在连接业务流程前将每个依赖映射为预定义的资源错误类型。
ResultAsync.resource
Pattern Transformations
模式转换
Throwing parse to Result
Result将抛出异常的解析转换为Result
Resultts
import { Result } from 'funkcia';
function parseWebhook(raw: string) {
return Result.try(
() => JSON.parse(raw),
() => new Error('Invalid webhook payload'),
);
}ts
import { Result } from 'funkcia';
function parseWebhook(raw: string) {
return Result.try(
() => JSON.parse(raw),
() => new Error('Invalid webhook payload'),
);
}Nullable lookup to Option
Option将可空查找转换为Option
Optionts
import { Option } from 'funkcia';
function findPrimaryEmail(user: User) {
return Option.fromNullable(user.emails.find((x) => x.primary))
.map((email) => email.value.toLowerCase());
}ts
import { Option } from 'funkcia';
function findPrimaryEmail(user: User) {
return Option.fromNullable(user.emails.find((x) => x.primary))
.map((email) => email.value.toLowerCase());
}Rejecting async call to ResultAsync
ResultAsync将拒绝的异步调用转换为ResultAsync
ResultAsyncts
import { ResultAsync } from 'funkcia';
function fetchCheckoutSession(sessionId: string) {
return ResultAsync.try(
() => payments.getSession(sessionId),
(cause) => new Error(`Failed to fetch session ${sessionId}: ${String(cause)}`),
);
}ts
import { ResultAsync } from 'funkcia';
function fetchCheckoutSession(sessionId: string) {
return ResultAsync.try(
() => payments.getSession(sessionId),
(cause) => new Error(`Failed to fetch session ${sessionId}: ${String(cause)}`),
);
}Callback Hell vs Generators
回调地狱 vs 生成器
Callback hell / nested async handling
回调地狱 / 嵌套异步处理
ts
async function buildCheckoutSummary(userId: string): Promise<Result<CheckoutSummary, CheckoutError>> {
try {
const user = await usersApi.getById(userId);
if (!user.defaultPaymentMethodId) {
return Result.error(new MissingPaymentMethodError(user.id));
}
const paymentMethod = await paymentsApi.getMethod(user.defaultPaymentMethodId);
const cart = await cartApi.getActiveCart(user.id);
if (!cart) {
return Result.error(new CartNotFoundError(user.id));
}
return Result.ok({
userEmail: user.email,
paymentMethod: paymentMethod.brand,
total: cart.total,
});
} catch (cause) {
return Result.error(new CheckoutInfrastructureError(cause));
}
}ts
async function buildCheckoutSummary(userId: string): Promise<Result<CheckoutSummary, CheckoutError>> {
try {
const user = await usersApi.getById(userId);
if (!user.defaultPaymentMethodId) {
return Result.error(new MissingPaymentMethodError(user.id));
}
const paymentMethod = await paymentsApi.getMethod(user.defaultPaymentMethodId);
const cart = await cartApi.getActiveCart(user.id);
if (!cart) {
return Result.error(new CartNotFoundError(user.id));
}
return Result.ok({
userEmail: user.email,
paymentMethod: paymentMethod.brand,
total: cart.total,
});
} catch (cause) {
return Result.error(new CheckoutInfrastructureError(cause));
}
}Preferred generator style
推荐的生成器风格
ts
function buildCheckoutSummary(userId: string): ResultAsync<CheckoutSummary, CheckoutError> {
return ResultAsync.use(async function* () {
const user = yield* ResultAsync.try(
() => usersApi.getById(userId),
(cause) => new CheckoutInfrastructureError(cause),
);
const paymentMethodId = yield* Result.fromNullable(
user.defaultPaymentMethodId,
() => new MissingPaymentMethodError(user.id),
);
const paymentMethod = yield* ResultAsync.try(
() => paymentsApi.getMethod(paymentMethodId),
(cause) => new CheckoutInfrastructureError(cause),
);
const cart = yield* Result.fromNullable(
yield* ResultAsync.try(
() => cartApi.getActiveCart(user.id),
(cause) => new CheckoutInfrastructureError(cause),
),
() => new CartNotFoundError(user.id),
);
return ResultAsync.ok({
userEmail: user.email,
paymentMethod: paymentMethod.brand,
total: cart.total,
});
});
}ts
function buildCheckoutSummary(userId: string): ResultAsync<CheckoutSummary, CheckoutError> {
return ResultAsync.use(async function* () {
const user = yield* ResultAsync.try(
() => usersApi.getById(userId),
(cause) => new CheckoutInfrastructureError(cause),
);
const paymentMethodId = yield* Result.fromNullable(
user.defaultPaymentMethodId,
() => new MissingPaymentMethodError(user.id),
);
const paymentMethod = yield* ResultAsync.try(
() => paymentsApi.getMethod(paymentMethodId),
(cause) => new CheckoutInfrastructureError(cause),
);
const cart = yield* Result.fromNullable(
yield* ResultAsync.try(
() => cartApi.getActiveCart(user.id),
(cause) => new CheckoutInfrastructureError(cause),
),
() => new CartNotFoundError(user.id),
);
return ResultAsync.ok({
userEmail: user.email,
paymentMethod: paymentMethod.brand,
total: cart.total,
});
});
}Reference Map
参考映射
- : Model real application failures with
references/tagged-errors.md.TaggedError - : Use
references/exhaustive.mdandexhaustivefor type-safe branching.corrupt - : Build branded domain primitives and safe parsers.
references/brand.md - : Use built-in exception types and
references/exceptions.md.panic - : Safely parse JSON and normalize URLs/URIs.
references/safe-functions.md - : Preferred generator-based style for
references/generators.md/Optionand async variants.Result - : Context-accumulation style with
references/do-notation.md,Do,bind, andlet.bindTo - : Wrap shared resources with
references/resources.mdso operations return expected values or pre-defined resource errors.ResultAsync.resource
- : 使用
references/tagged-errors.md为真实应用层失败建模。TaggedError - : 使用
references/exhaustive.md和exhaustive实现类型安全的分支处理。corrupt - : 构建带品牌标识的领域原语与安全解析器。
references/brand.md - : 使用内置异常类型与
references/exceptions.md。panic - : 安全解析JSON并标准化URL/URI。
references/safe-functions.md - :
references/generators.md/Option及其异步变体的推荐生成器风格。Result - : 使用
references/do-notation.md、Do、bind和let的上下文累积风格。bindTo - : 使用
references/resources.md包装共享资源,使操作返回预期值或预定义的资源错误。ResultAsync.resource