Wie stelle ich die Art der Ablehnung meines Versprechens ein? Sagen wir, ich tue:
const start = (): Promise<string> => {
return new Promise((resolve, reject) => {
if (someCondition) {
resolve('correct!');
} else {
reject(-1);
}
});
}
Nehmen wir an, ich möchte mit einer Nummer ablehnen. Aber ich kann den Typ nicht einstellen; Ich kann an die weitergeben, was ich will reject
hier.
Außerdem möchte ich bei der Verwendung dieses Versprechens einen Kompilierungsfehler haben, wenn ich den Ablehnungsantworttyp falsch verwende.
Wie in erklärt dieses Problem, Promise
hat keine unterschiedlichen Typen für erfüllte und abgelehnte Versprechen. reject
akzeptiert any
Streit das hat keinen Einfluss auf die Art eines Versprechens.
Zur Zeit Promise
besser kann man es nicht schreiben. Dies ergibt sich daraus, dass ein Versprechen abgelehnt werden kann throw
drinnen then
oder catch
(Dies ist ein bevorzugter Weg, um ein vorhandenes Versprechen abzulehnen), und dies kann nicht vom Typisierungssystem gehandhabt werden. Außerdem hat TypeScript auch keine ausnahmespezifischen Typen außer never
.
Da es in einigen Fällen wie Promise oder Ausnahmeauslösungen keine Möglichkeit gibt, den Fehlertyp festzulegen, können wir mit Fehlern im Rost-ähnlichen Stil arbeiten:
// 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;
}
}
});
Die Ausnahme ist typisiert Any, da wir den korrekten Typ der Ausnahme zur Entwurfszeit nicht garantieren können und weder TypeScript noch JavaScript die Möglichkeit bieten, Ausnahmetypen zur Laufzeit zu schützen.
Am besten verwenden Sie Typwächter, um sowohl eine Entwurfszeit- als auch eine Laufzeitprüfung in Ihrem Code bereitzustellen.
Quelle
Was @EstusFlask in seiner Antwort erwähnt hat, ist richtig.
Aber Ich möchte einen Schritt in die Nähe eines gehen künstliche Lösung zu
simulieren mit was wir wollen TypeScript
Fähigkeiten.
Manchmal verwende ich dieses Muster in meinen Codes😉:
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)
}
})
Sie können einen Proxy verwenden, um dies explizit zu erzwingen resolve
und reject
Argumenttypen. Das folgende Beispiel versucht nicht, den Konstruktor eines Versprechens nachzuahmen – weil ich das in der Praxis nicht nützlich fand. Ich wollte eigentlich telefonieren können .resolve(...)
und .reject(...)
als Funktionen außerhalb des Konstruktors. Auf der Empfängerseite wird das nackte Versprechen verwendet – z. 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 };
}
Das let
Anweisungen sehen aus, als wären sie sinnlos – und sie sind zur Laufzeit sinnlos. Aber es stoppt Compilerfehler, die sonst nicht einfach zu beheben wären.
(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);
})()
Ruft wie gezeigt an .resolve
und .reject
sind richtig typisiert überprüft.
Oben wird kein Versuch unternommen, eine Typenüberprüfung auf der Empfangsseite zu erzwingen. Ich habe mit dieser Idee herumgestochert und etwas hinzugefügt .then
und .catch
Mitglieder, aber was sollen sie dann zurückgeben? Wenn sie zurückkehren a Promise
dann wird es wieder zu einem normalen Versprechen, also ist es sinnlos. Und es scheint, dass es keine andere Wahl gibt, als das zu tun. Also wird das nackte Versprechen verwendet await
, .then
und .catch
.
11222100cookie-checkTypescript Promise-Ablehnungstypyes
Dieses Problem kann von Interesse sein.
– CRice
27. April 2018 um 22:58 Uhr