@ 字节/ 结果
结构化操作的轻量级类型脚本工具 Result 类型,减轻对例外处理锅炉板的需求.
此软件包使开发者能够清晰地代表两者 成功 财务报告和审定财务报表 失败 ,确保在管理业务成果时采取可预测和类型安全的办法.
由球队建造 : 字节Slice。 。 。 .
目录
动机
要充分理解这个一揽子计划的目的和应用,必须提供一些上下文.
错误对例外
在方案必须迅速终止以应对严重问题或意外情况的情况下,例外特别有用。 如该词所示,它们意味着 例外情况 当标准操作因出乎意料而中断时,就会产生这种情况.
在TypeScript中,任何值都可以被"推"为例外:出错,字符串,数字,你给它取名. 这就是为什么“抓取”例外是类型 unknown。 。 。 .
另一方面,错误是代表预期(尽管不受欢迎)行为的数值。 它们表示一种错误状态,通常包含一个解释问题性质的描述性信息.
函数签名
TypeScript - - - - - 在提供优秀类型的安全性的同时 - - - - 缺少内置机制来指示某个函数何时可以抛出例外.
考虑以下功能。 虽然执行表明可以提出例外,但类型签名未能传达这一信息.
function fetchUser(id: string): User {
throw new Error('Oh no, Mr. Bill!')
}
如果开发者不熟悉基本实施,这一点就变得特别有问题。 它们可能需要诉诸防御性尝试/捕获区块,或有意外传播例外的风险.
成功和失败国家
每个操作都会导致两种可能的结果之一:成败. 建立一个代表这两个潜在国家的标准模式至关重要.
这个 @byteslice/result 软件包通过一个 Result 类型可以有效捕捉这两个不同的状态.
与其简单地返回一个值(显示成功)或扔出一个例外(显示失败),不如返回一个类型安全 Result 这代表了两种结果.
概览
@byteslice/result 提供下列出口:
-
Result- 受歧视的工会,代表:- 成绩数字 :
{ data: S } - 失败数字 :
{ failure: F }
- 成绩数字 :
-
withResult- 一个同步函数包:- 执行所提供的操作.
- 完全没有例外.
- 回返a 成功 或者说 失败 对象而不是投掷.
-
unwrap编号 :expect- 逃生舱门(由Rust所启发) 返回 成功data直接投出,如果Result是一个失败. -
unwrapOr编号 :unwrapOrElse- 返回的(不扔出)提取器总数 成绩data,或当Result是一个失败. -
map编号 :mapFailure- 组合器(由Rust所启发) 成功data或failure穿过另一个州时.
这个模式在您想要时特别有用 避免使用尝试/捕获 直接在代码中,或者如果需要一种标准的方法来获取故障细节.
使用量
基本示例
import { withResult } from '@byteslice/result'
// function signature does not indicate an exception may occur
async function fetchData(): Promise<string> {
throw new Error('The dog refused to fetch')
}
async function main() {
const result = await withResult(
// operation
() => fetchData(),
// onError
(error) => new Error('Could not fetch data', { cause: error })
)
// check for failure
if (result.failure) {
console.error(result.failure)
} else {
// result is a success
// data property is now available
console.log(result.data)
}
}
main()
让我们检查一下 withResult 还:
- 第一个参数( E)
operation)包裹一个待执行的函数,当withResult名为.- 如果提供的函数抛出一个例外,则被强迫出错(视必要).
- 第二个参数( E)
onError) 接收此错误作为唯一的参数并返回 aFailureOption无论是Error或一个FailureCase(带有error(b) 财产). - 这个
Result从withResult取决于结果operation。 。 。 .- 若为 已经成功时,返回
Result将会是类型Success并在其data属性. - 若为 失败时,返回
Result将会是类型Failure并包含FailureOption联合国failure属性.
- 若为 已经成功时,返回
为确保处理失败状态 failure 财产的财产 Result 必须在 data 属性(及其强烈类型的内容)可以访问.
· 在上述例子中,
onError返回铃声Error时 维护堆栈跟踪 初始错误 原因。 。 。 .
自定义失败
默认情况下 Failure 类型 Result 包含一个 failure 财产 Error。 。 。 .
不过,你可以定义自己的习惯 failure- 只要它是一个物体 error 类型属性 Error。这将确保错误可用,同时允许灵活地添加任何其他字段.
import { withResult, Result } from '@byteslice/result'
type CustomFailure = {
// required property
error: Error
// custom property
type: 'NETWORK_ERROR' | 'VALIDATION_ERROR'
}
type CustomSuccess = { name: string }
async function fetchUser(): Promise<Result<CustomSuccess, CustomFailure>> {
return await withResult(
async () => {
// function call may throw an exception
const name = await db.getName()
return { name }
},
// onError returns custom failure
(error) => ({ error, type: 'NETWORK_ERROR' })
)
}
async function main() {
const result = await fetchUser()
if (result.failure) {
console.warn('This type of error occurred:', result.failure.type)
} else {
console.log(result.data.name)
}
}
main()
钩: onException
你可以选择提供 onException 将原例外转换为错误的钩子,然后传递到 onError。这是根据例外类型记录或返回自定义错误的好地方.
import { withResult } from '@byteslice/result'
async function main() {
const result = await withResult(
// operation may throw an exception
() => riskyOperation(),
// onError receives error returned from onException
(err) => (err),
{
onException: (ex) => {
// log thrown exception
console.warn('Caught exception:', ex)
// return known error
if (err instanceof CustomError) {
return err
}
// return default error
return new Error('Something unexpected occurred')
}
}
)
if (result.failure) {
console.error(result.failure)
} else {
console.log(result.data)
}
}
main()
若无 onException 钩子提供,然后任何抛出例外 由内部处理 ensureError 函数。 正如这个名字的意思,它确保 onError 钩子收到有效的错误 .
正在打开 : unwrap 财务报告和审定财务报表 expect
检查 failure 属性是安全、类型驱动的消费方式 Result然而,偶尔,你 知道吗 行动本应该成功的 并且只是想要 data——把任何故障都当作一个例外的,用程序吸气的事件处理.
借款人 红宝石 Result, (中文(简体) ), unwrap 财务报告和审定财务报表 expect 提供这个逃生舱门.
unwrap 返回成功 data,或者重推失败的内在错误.
import { unwrap, withResult } from '@byteslice/result'
const result = await withResult(
() => fetchData(),
(error) => error,
)
// returns the data on success, or throws the underlying error on failure
const data = unwrap(result)
expect 行为相同,但让你描述 为什么 预期会取得成功。 如果失败,它会扔出一个 Error ,通过 原因。 。 。 .
import { expect, withResult } from '@byteslice/result'
const result = await withResult(
() => loadConfig(),
(error) => error,
)
// throws `Error('config should be present', { cause: <original error> })` on failure
const config = expect(result, 'config should be present')
就像他们的Rust同事一样,
unwrap财务报告和审定财务报表expect贸易类型的安全方便。 只有当失败真正代表了无法恢复的状态时,才能接触到他们.
倒计时 : unwrapOr 财务报告和审定财务报表 unwrapOrElse
当失败应解决合理违约而不是例外时, unwrapOr 财务报告和审定财务报表 unwrapOrElse 还原成功 data 或退缩,而永不抛掷.
unwrapOr 需要急切的回落值.
import { unwrapOr, withResult } from '@byteslice/result'
const result = await withResult(
() => loadTimeout(),
(error) => error,
)
// returns the loaded timeout, or 5000 on failure
const timeout = unwrapOr(result, 5000)
unwrapOrElse 将函数计算出从 failure。只有在结果是失败时才引用它,使它成为懒惰的对手 unwrapOr。 。 。 .
import { unwrapOrElse, withResult } from '@byteslice/result'
const result = await withResult(
() => loadConfig(),
(error) => error,
)
// computes a fallback from the failure, only when needed
const config = unwrapOrElse(result, (failure) => {
console.warn('Falling back to defaults:', failure.message)
return defaultConfig
})
正在转换 : map 财务报告和审定财务报表 mapFailure
map 财务报告和审定财务报表 mapFailure 转换一面 Result 在经过另一边时,你无需手动解开并重新包装 Result。 。 。 .
map 改变成功 data。失败不改变返回,不引用映射函数.
import { map, withResult } from '@byteslice/result'
const result = await withResult(
() => fetchUser(),
(error) => error,
)
// Result<User, Error> → Result<string, Error>
const name = map(result, (user) => user.name)
QQ 映射函数被假定为不可失(它本身不能失败). 如果你的变换可能抛出, 把它包起来
withResult换句话说.
mapFailure 改变 failure。成功返回时不变,所绘制的失败本身必须是有效的失败——无论是 Error 或带有 error 属性.
import { mapFailure, withResult } from '@byteslice/result'
const result = await withResult(
() => fetchUser(),
(error) => error,
)
// enrich the failure with additional context
const tagged = mapFailure(result, (error) => ({
error,
type: 'NETWORK_ERROR' as const,
}))
捐款
请看 捐款额 详细情况.