错误fns
标准化的帮助错误和方法,以更简单,更安全,更容易读取代码.
目的
将有用的错误标准化,以便更简单、更安全、更容易读取代码
- 扩展
HelpfulError用于可观察和可操作的错误信息 - 杠杆作用
UnexpectedCodePath用收缩的代码路径消除复杂性 - 杠杆作用
BadRequestError当您的逻辑成功拒绝了请求时, 将它明确化 - 测试逻辑在工程学上投出错误
getError
安装
npm install --save @ehmpathy/error-fns
使用情况
意外代码路径错误
这个 UnexpectedCodePath 错误可能是您要丢出的最常见错误类型 .
在商业逻辑中很常见的是,你会面对一种技术上可能但逻辑上不应该发生的情景.
比如说你正在写车辆代码 检查车辆的轮胎压力.
// given the tires to check
const tires = Tire[];
// first get the tire pressures for each
const tirePressures: number[] = tires.map(tire => getTirePressure(tire));
// now get the lowest tire pressure
const lowestTirePressure: number | undefined = tires.sort()[0];
在这种情况下,从技术上讲 lowestTirePressure 无法定义 : 没有轮胎 .
然而,这绝对是一个意外的代码路径 对于我们的应用。 如果我们到达这里,我们可以停止我们的逻辑,因为我们不需要解决这个问题.
// sanity check that we do have a tire pressure
if (lowestTirePressure === undefined)
throw new UnexpectedCodePath('no tire pressures found. can not compute lowest tire pressure', { tires });
有了这个,类型 lowestTirePressure 已经从 number | undefined 仅仅 number,所以你不会再有任何类型错误.
此外,如果这个案件真的发生在现实生活中,那么就很容易调试所发生的事情和原因. 您的错误消息将包含 tires 输入导致问题 使这里成为调试的微风 。 没有了 could not read property 'x' of undefined来啊!
错误请求错误
这个 BadRequestError 可能是下一个最常见的错误类型.
在商业逻辑中常见的情况是,呼叫者会尝试用逻辑上完全无效的输入来执行你的逻辑. 用户可能无法理解他们的输入无效,或者可能只是上游有错误导致请求无效.
例如,想象一下,您有一个 Api 返回用户喜欢的歌曲
const getLikedSongsByUser = ({ userUuid }: { userUuid: string }) => {
// lookup the user
const user = await userDao.findByUuid({ uuid: userUuid });
// if the user does not exist, this is an invalid request. we shouldn't be asked to lookup songs for fake users
if (!user)
throw new BadRequestError('user does not exist for uuid', { userUuid });
// use a property of the user to lookup their favorite songs
const songs = await spotifyApi.getLikesForUser({ spotifyUserId: user.spotifyUserId });
}
不论来电者提出逻辑上无效的请求的原因为何,必须区分何时 您的代码 错在何时 请求 是错的.
这在监测出错率时特别有用. 区分您的软件是否重要 failed to execute 或者它是否已经 successfully rejected (c) 要求保持对问题的观察。 这个 BadRequestError 我们能轻松地做到
例如,图书馆,例如: 简单处理器 杠杆 BadRequestErrors 以确保错误的请求既能成功返回给调用者的错误,又不会被标记为羊肉达引用错误.
帮助错误
这个 HelpfulError 是这种模式的中枢 也是你将要看到的 extend 当您想要创建自定义错误时.
这个错误的目的,是尽量帮助那些在它被抛出时必须阅读它的人.
为了实现这一目标,错误使得非常容易具体说明问题是什么,以及可能有助于理解当时发生的原因的任何其他信息。 然后,它非常的打印这个信息 使它在观察时容易阅读.
throw new HelpfulError(
'the message of the error goes here',
{
context,
relevantInfo,
potentiallyHelpfulVariables,
goHere,
}
)
获取错误
这个 getError 方法就是这个库的上层樱桃.
当写出在某些情况下丢出错误的逻辑测试时,您可能想要验证代码是否确实将这个错误丢入测试中 .
这个 getError 实用性使得可以非常容易地断言预期出错.
在引擎盖下,它执行或等待你作为输入给出的逻辑或承诺,抓住所抛出的错误,或扔出自己的"不重推"(Norrorthrown Error). 它负责处理你可能需要使用的所有三个案件,并正确定义返回类型.
使用例1:同步逻辑
const doSomething = () => { throw new HelpfulError('found me'); }
const error = getError(() => doSomething())
expect(error).toBeInstanceOf(HelpfulError);
expect(error.message).toContain('found me')
使用大小写2:同步逻辑
const doSomething = async () => { throw new HelpfulError('found me'); }
const error = await getError(() => doSomething())
expect(error).toBeInstanceOf(HelpfulError);
expect(error.message).toContain('found me')
使用例3:承诺
const doSomething = async () => { throw new HelpfulError('found me'); }
const error = await getError(doSomething())
expect(error).toBeInstanceOf(HelpfulError);
expect(error.message).toContain('found me')
投掷
错误从 HelpfulError 列入a .throw 与三联体或条件链方便使用的静态方法
例如,代替
const phone = customer.phoneNumber ?? (() => {
throw new UnexpectedCodePathError(
'customer has relationship without phone number. how is that possible?',
{ customer },
);
})();
你只需写
const phone = customer.phoneNumber ?? UnexpectedCodePathError.throw(
'customer does not have a phone. how is that possible?',
{ customer },
);
帮助错误参数选项
.cause 参数是本地错误的一个有用特征. 它允许您将错误连在一起, 从而保留整个堆栈的痕量.
例如,有时,原始错误,即您的代码体验可以被重写来方便调试. 通过使用.cause 选项,您可以保留堆栈痕量和原始错误的引用,同时丢出一个新的,更有用的,错误.
// imagine you're using some api which throws an unhelpful error
const apiGetS3Object = async (input: { key: string }) => { throw new Error("no access") }
// you can catch and extend the error to add more context
const helpfulGetS3Object = async (input: { key: string }) => {
try {
await getS3Object();
} catch (error) {
if (error.message === "no access") throw HelpfulError("getS3Object.error: could not get object", {
cause: error, // !: by adding the "cause" here, we'll retain the stack trace of the original error
input,
})
}
}