Typescript Promise 拒绝类型
Posted
技术标签:
【中文标题】Typescript Promise 拒绝类型【英文标题】:Typescript Promise rejection type 【发布时间】:2018-10-08 19:31:34 【问题描述】:如何设置拒绝我的承诺的类型?假设我这样做:
const start = (): Promise<string> =>
return new Promise((resolve, reject) =>
if (someCondition)
resolve('correct!');
else
reject(-1);
);
假设我想用一个数字拒绝。但我无法设置类型;我可以在这里将任何我想要的东西传递给reject
。
此外,在使用这个promise时,如果我错误地使用了拒绝响应类型,我希望有编译错误。
【问题讨论】:
This issue 可能感兴趣。 【参考方案1】:您可以使用代理来显式强制使用 resolve
和 reject
参数类型。下面的例子并没有试图模仿 Promise 的构造函数——因为在实践中我没有发现它有用。我实际上希望能够将.resolve(...)
和.reject(...)
作为构造函数之外的函数调用。在接收方使用裸承诺 - 例如,await p.promise.then(...).catch(...)
。
export type Promolve<ResT=void,RejT=Error> =
promise: Promise<ResT>;
resolve: (value:ResT|PromiseLike<ResT>) => void;
reject:(value:RejT) =>void
;
export function makePromolve<ResT=void,RejT=Error>(): Promolve<ResT,RejT>
let resolve: (value:ResT| PromiseLike<ResT>)=>void = (value:ResT| PromiseLike<ResT>)=>
let reject: (value:RejT)=>void = (value:RejT)=>
const promise = new Promise<ResT>((res,rej) =>
resolve = res;
reject = rej;
);
return promise, resolve, reject ;
let
语句看起来好像毫无意义——它们在运行时毫无意义。但它会阻止那些不容易解决的编译器错误。
(async()=>
const p = makePromolve<number>();
//p.resolve("0") // compiler error
p.resolve(0);
// p.reject(1) // compiler error
p.reject(new Error('oops'));
// no attempt made to type the receiving end
// just use the named promise
const r = await p.promise.catch(e=>e);
)()
如图所示,对 .resolve
和 .reject
的调用已正确键入检查。
上面没有尝试在接收端强制进行类型检查。
我确实提出了这个想法,添加了.then
和.catch
成员,但是他们应该返回什么呢?如果他们返回一个Promise
,那么它又回到了一个正常的承诺,所以这是没有意义的。似乎别无选择,只能这样做。所以裸承诺用于await
、.then
和.catch
。
【讨论】:
【参考方案2】:由于在某些情况下无法设置错误类型,例如 Promise 或异常抛出,我们可以处理类似 rust 风格的错误:
// Result<T, E> is the type used for returning and propagating errors.
// It is an sum type with the variants,
// Ok<T>, representing success and containing a value, and
// Err<E>, representing error and containing an error value.
export type Ok<T> = _tag: "Ok"; ok: T ;
export type Err<E> = _tag: "Err"; err: E ;
export type Result<T, E> = Ok<T> | Err<E>;
export const Result = Object.freeze(
Ok: <T, E>(ok: T): Result<T, E> => ( _tag: "Ok", ok ),
Err: <T, E>(err: E): Result<T, E> => ( _tag: "Err", err ),
);
const start = (): Promise<Result<string, number>> =>
return new Promise((resolve) =>
resolve(someCondition ? Result.Ok("correct!") : Result.Err(-1));
);
;
start().then((r) =>
switch (r._tag)
case "Ok":
console.log(`Ok $r.ok `);
break;
case "Err":
console.log(`Err $r.err `);
break;
);
【讨论】:
我建议不要使用这种模式。问题是您现在有两种错误处理方式,一种是检查结果的错误类型,另一种是使用.catch
。你当然可以假设你的整个代码库只使用错误结果,但我向你保证,在任何规模很大的项目中,这种假设都会让你付出代价。
实际上它是函数式编程的模式,称为 Either,以及随之而来的所有后果
我知道,但这并不能改变我所说的。假设是导致问题的原因。此外,虽然Result
可能是一个真正的 sum 类型,但 Promise 不是一个 monad,所以你真的不在 FP 领域。我已经走这条路太多次了,不仅是使用 TypeScript。老实说,我应该有点宽容,因为在有人为 TypeScript 中的异步编程创建真正的一元双函子之前,我每次看到Promise
这个词都会感到畏缩。如果上帝给我多一点时间,我会成为那个人。
@GabrielC.Troia 哈哈!我最近找到了你的库,并把它展示给我们的前端技术负责人并告诉他:应该这样做:) 如果你碰巧找工作:欢迎随时在 StackState 工作!
@LodewijkBogaards 哇!!这绝对是我的早晨 :) 非常感谢您的客气话,先生。如果您最终在 StackState 使用它,我将非常乐意与你们合作。【参考方案3】:
@EstusFlask 在his answer 中提到的是正确的。
但是我想更接近人工解决方案 使用
TypeScript
功能模拟我们想要的。
有时我在我的代码中使用这种模式?:
interface IMyEx
errorId:number;
class MyEx implements IMyEx
errorId:number;
constructor(errorId:number)
this.errorId = errorId;
// -------------------------------------------------------
var prom = new Promise(function(resolve, reject)
try
if(..........)
resolve('Huuuraaa');
else
reject(new MyEx(100));
catch (error)
reject(new MyEx(101));
);
// -------------------------------------------------------
prom()
.then(success =>
try
catch (error)
throw new MyEx(102);
)
.catch(reason=>
const myEx = reason as IMyEx;
if (myEx && myEx.errorId)
console.log('known error', myEx)
else
console.log('unknown error', reason)
)
【讨论】:
【参考方案4】:异常键入 any 因为我们不能保证正确 设计时异常的类型,既不是 TypeScript 也不是 javascript 提供了在运行时保护异常类型的能力。 最好的选择是使用类型保护在代码中提供设计时和运行时检查。
source
【讨论】:
【参考方案5】:正如this issue 中所述,Promise
没有不同类型的已履行和已拒绝承诺。 reject
accepts any
argument 不会影响承诺的类型。
目前无法更好地键入Promise
。这是因为可以通过throw
ing 在then
或catch
中拒绝一个promise(这是拒绝现有promise 的更好方式),而这不能通过打字系统处理;还有,TypeScript also doesn't have exception-specific types except never
。
【讨论】:
注意这与捕获到的错误类型一致以上是关于Typescript Promise 拒绝类型的主要内容,如果未能解决你的问题,请参考以下文章
TypeScript 泛型:如果 Promise 拒绝和解析类型不同怎么办?
typescript async函数必需返回promise么
使用 Promise 的 TypeScript 异步类型保护