✈ 类型安全的扁平化的 try-catch,支持同步函数、回调函数和 PromiseLike
先看一段代码:
const somePromise = Promise.resolve({ prop: 'value' });
try {
// 块级作用域内赋值
// res类型推断为 {prop: string}
const res = await somePromise;
// 类型安全地使用 res
console.log(res.prop); // 'value'
} catch (err) {
// 此处 err 类型为 unknown
console.log(err);
}
但有些时候,我们需要将变量的声明提升到块级作用域外,比如:
const somePromise = Promise.resolve({ prop: 'value' });
// 需要先在 try-catch 块级作用域外定义变量,此处还需要先声明类型
// 由于只提升了声明,但没有提升赋值,需要捕捉期望的返回值类型,并联合 undefined
type Result = typeof somePromise extends Promise<infer T> ? T : never;
let res: Result | undefined;
try {
// 块级作用域内赋值
res = await somePromise;
// 块级作用域内类型仍然安全
console.log(res.prop); // 'value'
} catch (err) {
// 此处 err 类型为 unknown
console.log(err);
}
// 其他操作...
// try-catch 块级作用域外使用该变量
// 此处 res 类型包含 undefined,类型使用不安全
console.log(res.prop); // TS18048: 'res' is possibly 'undefined'.
// 所以还要加有值判断
if (res) {
console.log(res.prop);
}
可以看到,由于块级作用域的特性,导致 res 的类型被”污染“了, 使用 try-flatten 后,你将可以用一种“扁平化”的方式调用 try-catch, 不用为了类型安全写一些冗余代码。
import { tryFlatten } from 'try-flatten';
const somePromise = Promise.resolve({ prop: 'value' });
const [err, res] = await tryFlatten(somePromise);
// 只需要判断 err 是否存在即可
if (err) {
// 此处 err 类型为 Error,res 类型为 undefined
console.log(err instanceof Error); // true
console.log(res === undefined); // true
} else {
// 此处 err 类型为 null,res 类型为 Result
console.log(err === null); // true
console.log(res.prop); // 'value'
}
npm install try-flatten
import { tryFunction, tryFlatten } from 'try-flatten';
// 推荐使用 tryFunction
const [err, res] = tryFunction(() => 1);
// 与 tryFunction 同价
const [err, res] = tryFlatten(() => 1);
// 只需要判断 err 是否存在即可
if (err) {
// 此处 err 类型为 Error,res 类型为 undefined
console.log(err instanceof Error);
console.log(res === undefined);
return;
}
// 此处 err 类型为 null,res 类型为 number
console.log(err === null);
console.log(res === 1);
import { type Callback, tryCallback, tryFlatten } from 'try-flatten';
const cf = (cb: Callback<number>) => {
cb(null, 1);
};
// 推荐使用 tryCallback
const [err, res] = await tryCallback(cf);
// 与 tryCallback 等价
const [err, res] = await tryFlatten(cf);
// 只需要判断 err 是否存在即可
if (err) {
// 此处 err 类型为 Error,res 类型为 undefined
console.log(err instanceof Error);
console.log(res === undefined);
return;
}
// 此处 err 类型为 null,res 类型为 number
console.log(err === null);
console.log(res === 1);
import { type Callback, callbackCurry, tryCallback, tryFlatten } from 'try-flatten';
const cf = (a: number, b: number, cb: Callback<number>) => {
cb(null, a + b + 1);
};
// 推荐使用 tryCallback,不需要额外的 callbackCurry 辅助
const [err, res] = await tryCallback(cf, 1, 2);
// 与 tryCallback 等价
const [err, res] = await tryFlatten(callbackCurry(cf, 1, 2));
// 只需要判断 err 是否存在即可
if (err) {
// 此处 err 类型为 Error,res 类型为 undefined
console.log(err instanceof Error);
console.log(res === undefined);
return;
}
// 此处 err 类型为 null,res 类型为 number
console.log(err === null);
console.log(res === 4);
import { tryPromise, tryFlatten } from 'try-flatten';
// 推荐使用 tryPromise
const [err, res] = await tryPromise(Promise.resolve(1));
// 与 tryPromise 等价
const [err, res] = await tryFlatten(Promise.resolve(1));
// 只需要判断 err 是否存在即可
if (err) {
// 此处 err 类型为 Error,res 类型为 undefined
console.log(err instanceof Error);
console.log(res === undefined);
return;
}
// 此处 err 类型为 null,res 类型为 number
console.log(err === null);
console.log(res === 1);