Definitelytyped: bluebird 3.0: wie kann man es als Überladung für globales Versprechen verwenden?

Erstellt am 24. Aug. 2016  ·  44Kommentare  ·  Quelle: DefinitelyTyped/DefinitelyTyped

Hallo allerseits!

Ich verwende Bluebird als Ersatz für das globale Promise-Objekt. Ich habe versucht, Typedefs auf die neueste Version zu aktualisieren, die von @lhecker veröffentlicht wurde, und bin auf ein Problem gestoßen: global Promsie ist jetzt standardmäßig nicht überladen.
Wie kann ich vorheriges Verhalten erreichen? Vielleicht könnten wir zum Beispiel bluebird-global.d.ts haben?

Hilfreichster Kommentar

Hallo Leute,

@types/bluebird-global ist jetzt verfügbar. Diese Typisierungen verwenden @types/bluebird@^3.0 unter der Haube und erlauben Ihnen, die Methoden von bluebird auf dem globalen Promise zu verwenden (dh die Kompilierung von ts schlägt nicht fehl).

Bitte lesen Sie dies , um zu sehen, wie Sie es verwenden.

Alle 44 Kommentare

Nun, meiner Meinung nach waren die vorherigen Bluebird-Definitionen auch keine gute Lösung, da sie stark in den globalen Namensraum eingedrungen sind, und ich denke, es war eine gute Idee, redundante Bemühungen zu reduzieren.

Die vorherigen Definitionen funktionierten jedoch so, dass declare var Promise: PromiseConstructor; definiert wurde, während PromiseConstructor die vorherige (global definierte) Bluebird-Schnittstelle war.

Das heißt, wenn Sie eine lokale *.d.ts -Datei erstellen und so etwas hinzufügen, könnte es vielleicht funktionieren?

import Bluebird = require("bluebird");
declare var Promise: Bluebird<any>;

es könnte vielleicht funktionieren?

Unglücklicherweise nicht. Weil ich eine Menge Code habe, der so geschrieben ist:

declare function doLoadData(): Promise<Data>

Wie Sie sehen können, gibt die Funktion Promise<T> zurück, was dem Standard Promsie entspricht, nicht Bluebird. Deklaration var Promise: Bluebird<any> Ich werde den Standard-Promise-Konstruktor überladen, nicht die Schnittstelle.

Aus diesem Grund bin ich wieder auf die 2.0-Typisierungen umgestiegen.

@Strate Ah verdammt, ich habe einen langen Kommentar darüber geschrieben, was ich darüber denke und was wir versuchen sollten. Aber anscheinend habe ich vergessen, es einzureichen, und es war schließlich verloren ...

Viele Leute scheinen dieses Problem zu haben.

Ich habe ein Repo erstellt, das das Problem zeigt: https://github.com/d-ph/typescript-bluebird-as-global-promise

git-Klon && npm install && npm run tsc

Das Problem:
d.ts -Dateien von Drittanbietern werden gegen Promise typisiert. Dieses Promise wird entweder durch lib.es6.d.ts von Typoskript definiert (wenn "target": "es6" ) oder durch andere Bibliotheken, z. B. core-js (sehr beliebt, wenn mit Typoskript nach es5 kompiliert wird) . Das neueste bluebird.d.ts wird nicht als globales Promise deklariert, obwohl bluebird.js sich als globales Promise .

Ergebnis:
Entwickler können die Funktionalität von Bluebird nicht auf die Promises anwenden, die vom Code eines Drittanbieters zurückgegeben werden (Kompilierung schlägt fehl).

Erwartetes Ergebnis:
Entwickler können die Funktionalität von bluebird auf den Promises verwenden, die von Drittanbietercode zurückgegeben werden (Kompilierung erfolgreich).

Ich bin mir nicht sicher, wer der Betreuer von bluebird typings ist. @lhecker , du bist die unglückliche Person, die von git blame zurückgegeben wird. Können Sie uns sagen, was der bevorzugte Grund dafür ist, Bluebird-Eingaben so zu verwenden, dass das Github-Projekt, das ich oben verlinkt habe, kompiliert?

Aktuelle Walkarounds:

  1. Das dreckigste. Importieren Sie niemals Bluebird und verwenden Sie niemals Bluebird-Typisierungen. Verwenden Sie für bluebird Promise -Funktionen dies: Promise["config"]({}); Promise.resolve("foo")["finally"](() => { console.log("lol"); }) , um den Compiler stumm zu schalten. Dh verwenden Sie den Array-Zugriffsoperator: [""]
  2. Dreckig und nervig. Fügen Sie in jeder Eintrags-ts-Datei in Ihrer Anwendung diese beiden Zeilen hinzu:
import * as Bluebird from 'bluebird';
declare global { export interface Promise<T> extends Bluebird<T> {} }

Verwenden Sie für die statischen Funktionen von Bluebird Bluebird.config({}) anstelle von Promise.config({}) .

Der Nachteil ist, dass IDEs Schwierigkeiten haben, diesen Hack richtig zu interpretieren.

Hmm ... Es war irgendwie unvorhergesehen für mich, dass Sie Probleme damit haben werden, da Sie alle Bluebird auf eine Weise verwenden, wie ich und viele andere es nicht tun. Tatsächlich habe ich die Typisierungen nicht einmal selbst geschrieben! Ich habe einfach die einzigen existierenden für 3.0 von hier kopiert, denn irgendwelche Eingaben für 3.0 zu haben ist besser als keine, oder?

Die Sache ist die, dass die aktuelle Richtung, in die TypeScript geht, eindeutig modules > globals ist, was ich wirklich gutheiße. Das bedeutet aber auch, dass Module niemals globale Objekte modifizieren sollten, besonders wenn man bedenkt, dass Bluebird nicht in jedem Fall das globale Promise ersetzt! Oder um es so auszudrücken:

Was passiert mit Ihrer "Typsicherheit", wenn Sie irgendwo in Ihrem Code buchstäblich Promise.noConflict() aufrufen? Es wird den globalen Promise -Typ auf den ursprünglichen zurücksetzen und Ihren Code zum Absturz bringen, obwohl tsc Ihnen gesagt hat, dass alles in Ordnung ist.

Also ja ... @d-ph. Ihr zweiter Rundgang ist das, was Sie die ganze Zeit über in Betracht gezogen haben sollten, da er im Geiste von Modulsystemen ist. Aber ich weiß, dass dies nur für Bibliotheken die ideale Lösung ist, während es für Anwendungen wirklich lästig sein _kann_. Ich stimme zu, dass Anwendungssysteme auf jeden Fall zumindest in der Lage sein sollten, das globale Promise -Objekt zu ersetzen und dann auch die passenden Typisierungen für diesen Anwendungsfall haben sollten, wie sie in 2.0 verfügbar waren.

Letztendlich denke ich, dass angesichts der Ideologie von TypeScript die Erweiterung des globalen Promise -Typs _sehr_ sorgfältig erfolgen sollte (denken Sie an das noConflict() -Problem usw.) und wenn ja, nur als Opt-in.

IMO ist der Weg nach vorn, eine bluebird-global.d.ts (oder ähnliche) Datei irgendeiner Art zu schreiben, die das globale Promise -Objekt mit denselben Schnittstellendeklarationen erweitert, die in der bluebird.d.ts -Datei gefunden werden. Und wenn Sie diese verwenden müssen, sollten Sie sie explizit importieren müssen, anstatt sie immer enthalten zu haben. Auf diese Weise können Sie für die meisten Anwendungsfälle und insbesondere beim Schreiben von Bibliotheken sichere _und_ korrekte Eingaben vornehmen und gleichzeitig Zugriff auf die zusätzlichen Vorteile des Überschreibens der globalen Promise in Anwendungen haben.

Wenn Sie diese Idee gut finden und noch etwas Zeit übrig haben, wäre es cool, wenn Sie eine PR erstellen könnten. Über einen solchen Beitrag würden sich sicher viele sehr freuen. 🙂

Ich formuliere das so, weil ich aus Zeitgründen derzeit nicht in der Lage bin, solche Typisierungen zu schreiben und solche Typisierungen im Moment nicht benötige. Ich hoffe du kannst das verstehen.

@lhecker Ich denke, ich könnte dir zustimmen. Denn wenn wir Promise global auf Bluebird überschreiben, werden wir nur den Typoskript-Compiler hacken, aber nicht die reale Welt. Zum Beispiel wird bei überschriebenem Promise Typescript davon ausgegangen, dass fetch das von Bluebird zurückgibt:

import `whatwg-fetch`;
let result = fetch("anyurl"); // this is NOT bluebird promise, but typescript think that it is.

Ohne fetch in Promise.resolve $ von bluebird zu packen, erhalten Sie beispielsweise die Methode .finally nicht auf result :

import `whatwg-fetch`;
fetch("anyurl").then().finally() // goes to runtime error with overriden global promise, but should be compile error.

Daher denke ich, dass das explizite Importieren bluebird bei jeder Verwendung die bessere Lösung ist:

import Promise from "bluebird";
import `whatwg-fetch`;
Promise.resolve(fetch("anyurl")).then().catch() // no compile error, no runtime error

Ich werde meinen Code umgestalten.

Danke für deine Antwort, @lhecker .

Ich stimme allem zu, was Sie gesagt haben. Und ich mag die Lösung von @Strate , den Code von Drittanbietern mit der Methode Promise.resolve() zu verpacken, um das Versprechen von es6 in das von Bluebird umzuwandeln (oder das von Bluebird in das von Bluebird, weil ich das Versprechen von Bluebird in der Laufzeit global halten möchte, also ziehe ich es an Sie müssen sich nicht auf den Code von Drittanbietern verlassen, um ihre Fehler korrekt zu behandeln, aber das ist nebensächlich).

Es sieht so aus, als hätte ich nicht gewusst, wie man das richtig macht. Wovon meiner Meinung nach andere profitieren würden, ist mehr Dokumentation zum Umgang mit diesem Problem, da jeder, der aus der Welt der Browserprogrammierung kommt (im Gegensatz zu: von nodejs/typescript), darauf trifft, nachdem er:

  1. npm install <absolutely everything that uses es6 promise>
  2. npm install bluebird @types/bluebird
  3. Verwenden Sie den Drittanbietercode mit Typoskript

Ich würde auch davon profitieren, wenn dieser Abschnitt „So verwenden Sie den Code von Drittanbietern, wenn er gegen das es6-Versprechen eingegeben wird“ irgendwo für zukünftige Referenzen dokumentiert ist. Dh mit dem

import * as Bluebird from 'bluebird';
declare global { export interface Promise<T> extends Bluebird<T> {} }

und

import * as Promise from 'bluebird';
import { Observable } from "rxjs";

let observable = Promise.resolve(new Observable<number>().toPromise());

in einer Readme-Datei oder im Doc-Block oben in der Datei bluebird.d.ts.

Was denkst du?

Ich habe die Umstellung von der globalen Überschreibung von Promise auf Bluebird abgeschlossen und einige Probleme gefunden, bei denen Bibliotheken von Drittanbietern ES6 Promise zurückgeben, das als das von Bluebird behandelt wurde. Dieser Schritt hat also auch meine Codebasis aufgeräumt. Ich würde jedem empfehlen, von der globalen Überlastung von Promise . Beifall :)

Ich verstehe modules > globals , aber sagen wir aus Gründen der Argumentation (und/oder der Realität), dass ich an einem großen Browser-SPA arbeite und mit der Verwendung von Bluebird als Polyfill unseres Versprechens beauftragt wurde.

Ich versuche die von @lhecker vorgeschlagene bluebird-global.d.ts -Korrektur mit dem Inhalt von @d-ph:

import * as Bluebird from 'bluebird';
declare global { export interface Promise<T> extends Bluebird<T> {} }

Ich habe es über typings installiert, wodurch mein typings/modules/bluebird-global/index.d.ts generiert wurde:

// Generated by typings
// Source: src/bluebird-global.d.ts
declare module 'bluebird-global' {
// via https://github.com/DefinitelyTyped/DefinitelyTyped/issues/10801
import * as Bluebird from 'bluebird';
global { export interface Promise<T> extends Bluebird<T> {} }
}

Wenn ich jedoch versuche, alles zu erstellen, beschwert sich TypeScript (v1.8.2):

ERROR in /path/to/typings/modules/bluebird-global/index.d.ts
(6,27): error TS2665: Module augmentation cannot introduce new names in the top level scope.

ERROR in /path/to/src/bluebird-global.d.ts
(2,35): error TS2665: Module augmentation cannot introduce new names in the top level scope.

Ich habe mir das MS-Beispiel für global-modifying-module.ts
https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-modifying-module-d-ts.html

Und ein TS-Problem im Zusammenhang mit dieser Fehlermeldung
https://github.com/Microsoft/TypeScript/issues/6722

Aber ich weiß nicht, was ich tun sollte. Kann jemand helfen?

Hallo.

Könnten Sie mein Repo überprüfen, das das Problem und die Lösung zeigt? verlinken . Ich war ziemlich zufrieden damit, bis ich mich entschied, alle Versprechen von Drittanbietern in den Promise-Konstruktor von bluebird zu packen, was ich jetzt tue. Könnten Sie bestätigen, dass Sie, nachdem Sie die Schritte in der Readme-Datei befolgt haben, nicht kompilieren können, aber nachdem Sie die

// declare global {
//     export interface Promise<T> extends Bluebird<T> {}
// }

es kompiliert?

Denken Sie daran, dass mein Repo TS 2 verwendet (das jetzt stabil ist) und Sie sagten, Sie verwenden 1.8.2. Überprüfen Sie einfach, was passiert, wenn Sie TS auf 2 aktualisieren.

Schließlich hatte ich einige Probleme damit, meine Lösung in meine globale d.ts -Datei einzufügen. Am Ende fügte ich es jedem Einstiegspunkt meiner Webpack-Zusammenstellung hinzu, wodurch das Problem gelöst wurde (was für mich jetzt Sinn macht). Ich kenne Ihr js-Setup nicht, aber könnten Sie versuchen, meinen Fix in jede Datei zu packen, die während der Kompilierung fehlschlägt (oder zumindest eine davon), und prüfen, ob es hilft?

Ich möchte auch in der Lage sein, die Promise -Implementierung von Bluebird als globales Promise zu "registrieren". Ich habe diesen ganzen Thread gelesen, aber ich kann einem Teil nicht folgen. Der Teil, der vorschlägt, dass Bibliotheken von Drittanbietern weiterhin die native (z. B. Nicht-Bluebird) Promise -Implementierung zurückgeben. Wie könnte das sein, wenn dieser Drittanbietercode irgendwann den Promise -Konstruktor ( new Promise(...) ) aufruft, der auf globaler Ebene durch die Bluebird-Implementierung ersetzt wurde?

<script src="//.../bluebird.min.js"></script>
<script>
    var promise = fetch("some url");

   promise.finally(...); 
</script>

Sollte das nicht funktionieren, da ich Bluebird eingebunden habe, das die native Promise -Implementierung ersetzt hat?

Wenn ich diese vollständige globale Ersetzung zur Laufzeit durchführe, sollte ich schließlich in der Lage sein, TypeScript darüber zu informieren, sodass zur Kompilierzeit alle Promises ebenfalls durch Bluebird ersetzt werden.

Was vermisse ich?

Wenn Sie die dist-Version von Bluebird verwenden (was Sie tun), verwenden Bibliotheken von Drittanbietern Bluebird, da das globale Promise jetzt Bluebird ist. Sie verstehen diesen Teil richtig. Die Leute erwähnen etwas anderes, weil sie über die Verwendung von node.js durch Bluebird sprechen.

In diesem ganzen Thread geht es um die nicht so offensichtliche Art, ts mit dieser Annahme zu kompilieren (dass globales Versprechen Bluebird ist). Wenn Sie es geschafft haben (zB über das Ding declare global {} ), dann sind Sie fertig.

@d-ph Aber mein Takeaway ist, dass ich das in jeder *.ts -Datei und nicht nur einmal tun muss - ist das richtig? Vielleicht wäre eine Zusammenfassung der endgültigen "Lösung" für dieses Problem gut. :)

Ja, sehen Sie, es gibt hier keine einfache just copy&paste this line to your X file and everyone and their dog are happy now Lösung. Oder zumindest ist es mir nicht bewusst.

Das letzte Mal, als ich dich überprüft habe, entweder:

  1. Kopieren Sie die Zeile import * as Bluebird from 'bluebird'; declare global { export interface Promise<T> extends Bluebird<T> {} } und fügen Sie sie in jede *.ts-Datei des Einstiegspunkts ein , oder
  2. jedes Versprechen, das vom Code eines Drittanbieters zurückgegeben wird, in die Konstruktorfunktion von Bluebird packen. In der Laufzeit wird es nichts tun (außer unnötigem Laufzeit-Overhead) und in der Kompilierzeit wird es TS glücklich machen.

Auch hier erfordert Lösung 1., dass dieser Code nur in Einstiegspunktdateien eingefügt wird, nicht in jede Datei. Zumindest hat das bei mir funktioniert (Webpack + Awesome-TypeScript-Loader).

Wenn Sie eine andere Lösung finden, bei der Entwickler buchstäblich nur 1 Zeile in 1 Datei einfügen müssen, teilen Sie dies bitte mit der Community ;p

Danke @d-ph - können Sie bestätigen, was Sie mit "jedem Einstiegspunkt *.ts-Datei" meinen?

Ja. "Einstiegspunkt" .ts-Datei ist die .ts-Datei, die Sie über das <script> -Tag in Ihr HTML laden. Mit anderen Worten, dies ist die Datei, von der aus die Kompilierung beginnt.

Nach kurzem Googeln habe ich das hier gefunden (nicht die Mühe machen, es zu lesen). Das Fazit ist, dass Sie, wenn Sie manuell global { export interface Promise<T> extends Bluebird<T> {} } in bluebird.d.ts hinzufügen, dies an keiner anderen Stelle erneut erwähnen müssen. Ich habe jetzt keine Zeit, es zu testen, aber ich habe es mit dem von mir erstellten Test-Github-Repo getestet, und es scheint zu funktionieren.

Mit anderen Worten, laden Sie bluebird.d.ts herunter und ändern Sie dies:

// Generated by typings
// Source: bluebird.d.ts
declare module 'bluebird' {
// Type definitions for Bluebird v3.x.x
// Project: http://bluebirdjs.com

class Bluebird<R> implements Bluebird.Thenable<R>, Bluebird.Inspection<R> {

dazu:

// Generated by typings
// Source: bluebird.d.ts
declare module 'bluebird' {
// Type definitions for Bluebird v3.x.x
// Project: http://bluebirdjs.com

global { export interface Promise<T> extends Bluebird<T> {} }

class Bluebird<R> implements Bluebird.Thenable<R>, Bluebird.Inspection<R> {

Offensichtlich ist dies nicht ideal, besonders wenn Sie @types/bluebird verwenden (das Sie jetzt entfernen müssten, weil Sie Ihr benutzerdefiniertes gehacktes bluebird.d.ts verwenden würden), aber gut ...

Ich habe also bereits eine _stubs.d.ts -Datei, zu der ich Folgendes hinzugefügt habe, und ich bin viel näher dran. Keine Beschwerden mehr darüber, dass finally auf Promise $ nicht existiert, aber aus irgendeinem Grund erhalte ich immer noch Fehler, dass delay auf Promise $ nicht existiert. Ich musste bluebird.d.ts nicht bearbeiten. Werde es untersuchen, aber das könnte eine großartige Lösung sein!

declare module "bluebird-global" {
    import * as Bluebird from "bluebird";

    global { export interface Promise<T> extends Bluebird<T> { } }
}

Bearbeiten: Mein Problem mit delay war, weil ich es statisch aufgerufen habe, zB Promise.delay(2000) .

Mit der oben geposteten Lösung erhalte ich diesen Fehler, wenn meine Funktion ein Promise<T> zurückgibt:

Fehler TS2322: Geben Sie „Bluebird' ist nicht dem Typ 'Promise' zuordenbar'.

Ich denke, das liegt daran, dass jetzt, da ich Promise durch Bluebird ersetzt habe, immer dann, wenn ich then usw. verwende, der Rückgabewert stattdessen ein Bluebird<T> ist von Promise<T> .

Hier ist meine endgültige Version dieses Hacks. Ich mag das nicht, aber ich mag es besser als die anderen Optionen. Grundsätzlich muss ich Dinge wiederholen, die ich auf der Schnittstelle verwende, indem ich den Rückgabetyp in Promise anstelle von Bluebird . Dies ist ein direktes Kopieren und Einfügen aus der anderen Bluebird-Definitionsdatei.

_stubs.d.ts

declare module "bluebird-global" {
    import * as Bluebird from "bluebird";

    global {
        export interface Promise<T> extends Bluebird<T> {
            then<U1, U2>(onFulfill: (value: T) => U1 | Bluebird.Thenable<U1>, onReject: (error: any) => U2 | Bluebird.Thenable<U2>): Promise<U1 | U2>;
            then<U>(onFulfill: (value: T) => U | Bluebird.Thenable<U>, onReject: (error: any) => U | Bluebird.Thenable<U>): Promise<U>;
            then<U>(onFulfill: (value: T) => U | Bluebird.Thenable<U>): Promise<U>;
            then(): Promise<T>;

            finally<U>(handler: () => U | Bluebird.Thenable<U>): Promise<T>;
        }
    }
}

Es wäre großartig, eine offizielle Definition bluebird-global oder bluebird-override zu haben, die der bestehenden Definition sehr ähnlich sieht, aber überall Promise anstelle von Bluebird verwendet.

Schön, dass du eine Lösung finden konntest.

Nur der Vollständigkeit halber: wie @ProTip sagte, mit bluebird-2.0.d.ts JustWorksTM. Installieren Sie es einfach mit npm install @types/[email protected] und fügen Sie es zu compilerOptions.types von tsconfig.json hinzu:

{
    "compilerOptions": {
//     (...)
        "types": [
          "bluebird"
        ]
    },
    "include": [
        "src/**/*.ts"
    ]
}

Alle Unterschiede zwischen dieser .d.ts-Datei und der aktuellen Bluebird-Version (dh 3.x) empfehle ich, manuell zu hacken.

Mit JustWorksTM meine ich: es funktioniert für:

a) es5-Ziel
b) es6-Ziel
c) es5-Ziel mit Core-js-Lib

unabhängig davon, ob jemand ein Build-Setup (Webpack + awesome-typescript-loader) verwendet oder nicht. Außerdem ist PhpStorm IDE überhaupt nicht verwirrt.

Ich habe heute einige Zeit damit verbracht, mich mit diesem Problem zu befassen, und tatsächlich diese beiden Tickets in Microsoft/TypeScript erstellt/aktualisiert: https://github.com/Microsoft/TypeScript/issues/10178 und https://github.com/Microsoft/TypeScript /issues/12382 . Meine Idee ist, wie Sie sagten (und einige vor Ihnen), dass wir eine bluebird-global.d.ts -Datei brauchen. Um doppelten Code zu vermeiden, fand ich, dass dies funktionieren würde:

// bluebird-global.d.ts

import * as Bluebird from "bluebird";

export as namespace Promise;
export = Bluebird;

vorausgesetzt, dass die beiden oben genannten Tickets gelöst oder Workarounds gefunden werden. In der Zwischenzeit empfehle ich die Verwendung des bluebird-2.0.d.ts, wenn für den Browser codiert wird.

@JoshMcCullough

Wie könnte das sein, wenn dieser Code von Drittanbietern irgendwann den Promise-Konstruktor (neues Promise (...)) aufruft, der auf globaler Ebene durch die Bliebird-Implementierung ersetzt wurde?

Ziemlich einfach. Versuchen Sie es in der Konsole Ihres Browsers (bevorzugt Chrome):

var NativePromise = Promise;
window.Promise = function() {}; // try to overload NativePromise
NativePromise === Promise; // false. Seems it is overloaded!
// And now, let check with some native code, which return Promise, for example fetch
Object.getPrototypeOf(fetch("")) === Promise.prototype; // false, Whoops!
Object.getPrototypeOf(fetch("")) === NativePromise.prototype; // true! Double whoops!

Hallo. Ich habe dies getan und es ist ziemlich glatt. Zunächst einmal sollten Sie sich bei Bibliotheksprojekten nicht auf bluebird verlassen. Importieren Sie für das Anwendungsprojekt bluebird, aber nicht die Typisierungen. Gehen Sie am Einstiegspunkt Ihrer Anwendung wie folgt vor:

global['Versprechen'] = require('bluebird')

Dadurch wird das globale Promise-Objekt für die Anwendung und alle enthaltenen Bibliotheken ersetzt.

Hallo Leute,

@types/bluebird-global ist jetzt verfügbar. Diese Typisierungen verwenden @types/bluebird@^3.0 unter der Haube und erlauben Ihnen, die Methoden von bluebird auf dem globalen Promise zu verwenden (dh die Kompilierung von ts schlägt nicht fehl).

Bitte lesen Sie dies , um zu sehen, wie Sie es verwenden.

Super, danke @d-ph!

@d-ph Danke für die @types/bluebird-global . Muss ich in meinem Projekt irgendeine Art von Import und Neuzuweisung vornehmen, um bluebird als Ersatz für das globale Promise zu verwenden?

npm install --save-dev @types/bluebird-global und befolgen Sie dann die Anweisungen, die ich in die Eingaben eingefügt habe: Link (Link aktualisiert am 2017-04-02). Dies allein sollte ausreichen (dh es sollten keine manuellen Importe/Neuzuweisungen erforderlich sein).

Als Nebenbemerkung: Sie müssen @types/bluebird nicht mehr in Ihrem package.json::devDependencies erwähnen, da dies automatisch impliziert wird.

Update zum Link im vorherigen Kommentar: link

@MichaelTontchev @d-ph Besteht die Möglichkeit, dass die Promise.Inspection -Schnittstelle zu bluebird-global hinzugefügt wird?

Hallo @ksnyde.

Bitte sprich mit mir. Ich bin der Betreuer.

Könnten Sie bitte bestätigen, dass Sie sich auf diese Promise.Inspection beziehen?

Alle Methoden dieser Schnittstelle werden über bluebird-global . Dh Folgendes wird kompiliert:

let promiseInspectionTest = new Promise<void>((resolve) => {});
promiseInspectionTest.value();

Es scheint mir also, dass Sie anfordern, dass dies als Promise.Inspection von bluebird-global wird.

Können Sie mir sagen, ob dies ein großer Rückschlag für Sie ist, stattdessen Folgendes zu verwenden:

import * as Bluebird from "bluebird";

class Foo<T> implements Bluebird.Inspection<T> {

}

Da Sie bluebird-global verwenden, können Sie auch die ursprünglichen bluebird -Typisierungen ohne explizite devDependencies $ importieren.

Ich würde das globale Promise ohne triftige Gründe lieber nicht weiter ausdehnen, weil es eine subtile Kunst ist, diese Typisierungen mit den Standard-Promise-Typisierungen von lib.d.ts zum Laufen zu bringen. Ich empfehle wirklich, direkt von den bluebird -Eingaben aus auf diese Schnittstelle zuzugreifen, da eines Tages JavaScript-Gurus Promise.Inspection zum Standard hinzufügen könnten, was die bluebird-global -Eingaben brechen würde, was die Folge wäre unnötige Probleme für die Endbenutzer verursachen.

Selbst wenn ich die Schnittstelle hinzufügen würde, müssten Sie eine unbestimmte Zeit warten, bis sie mit master zusammengeführt wird, da die Betreuer von DT heutzutage mit PRs beschäftigt sind.

Beifall.

Ich habe in der Tat den Ansatz verwendet, den Sie vorerst besprochen haben, und es ist eine angemessene Umgehung. Oder vielleicht ist "umgehen" die falsche Nomenklatur.

Mein Verständnis/meine Wahrnehmung war, dass die Idee hinter bluebird-global darin bestand, die Obermenge der Promise-Funktionalität bereitzustellen, die bluebird bereitstellt. In diesem Fall _würde_ ich als Benutzer erwarten, dass Bluebird.Inspection bei Promise.Inspection verfügbar gemacht wird. Wenn Sie jedoch eher sicherstellen möchten, dass die offizielle API-Oberfläche von Promises Bluebird verwendet, dann denke ich, dass diese "Umgehung" tatsächlich eine angemessene langfristige Lösung ist.

Obwohl ich meine Interpretation bevorzuge, kann ich bei Bedarf die hier vorgestellte Lösung verwenden.

Während ich sicherlich verstehe, woher Sie mit Ihren Erwartungen kommen, war der Hauptgrund, warum ich bluebird-global erstellt habe, TypeScript mitzuteilen, dass Promises, die von Drittanbietercode erstellt und zurückgegeben werden, tatsächlich Instanzen von Bluebird-Promises sind, zu denen es gab keine andere _nicht lästige_ Alternative, als alle Instanzen und statischen Methoden von Bluebird auf dem globalen Promise-Symbol verfügbar zu machen. Wie ich bereits erwähnt habe, ist die Art und Weise, wie es gemacht wird, kein einfaches class Promise<T> extends Bluebird<T> {} (obwohl es ursprünglich so war), sondern eher ein sorgfältig gepatchtes globales Versprechen-Symbol. Und wie gesagt, ich möchte lieber vermeiden, irgendetwas warten zu müssen, wofür es eine bekannte Alternative gibt, was einem nicht buchstäblich die Haare aus dem Kopf raufen lässt.

Tut mir leid, dass ich zu diesem "Nein" gesagt habe. Wenn es mehr Leute gibt, die dieses spezielle Feature anfordern, werde ich es überdenken, es hinzuzufügen. Ich möchte hier nicht autoritär klingen – dies ist ein Open-Source-Projekt und jeder könnte dieses Feature wahrscheinlich einführen. Der Punkt, den ich hier zu vermitteln versuche, ist, dass meiner Meinung nach der Vorteil darin liegt die Wartungskosten nicht aufwiegen.

Beifall.

macht Sinn. vielen Dank für die Gedanken hinter Ihrem Ansatz.

@d-ph macht das Folgende für Sie Sinn ... Ich erhalte eine Fehlermeldung, die besagt, dass "reflektieren" keine Funktion im folgenden Code ist:

image

Und während in der Intelisense des Editors korrekt identifiziert wird, dass die Eigenschaft p in der Zuordnungsfunktion ein Bluebird-Versprechen ist und die erweiterte API-Oberfläche hat, die nur auf Bluebird zu finden ist (im Gegensatz zu Promise).

image

Ich kann einfach nicht Kopf oder Zahl daraus machen. Ich habe bemerkt, dass, wenn ich den _type_ der Iterator-Variablen der Karte untersuche, es so angezeigt wird:

image

Ich nahm an, dass dies letztendlich der Grund ist, warum ich die durch bluebird-global definierte eingeschränkte API-Oberfläche bekomme, aber ich weiß nicht, warum sie nicht richtig aufgelöst wird.

Hallo.

Ich kann nicht reproduzieren :/ Diese Codeschnipsel funktionieren in meinem Setup.

Zunächst. Sie verwenden bluebird-global nicht in Ihrer Funktion allSettled() . Sie geben direkt mit Bluebird ein. Das ist kein Problem, aber vielleicht war es Ihnen nicht bewusst. Das folgende Snippet verwendet bluebird-global :

function allSettled<T>(promises: Array<Promise<T>>) {
    const reflections = Promise.all<T>(promises.map((promise => {
        return promise.reflect();
    })));

    return reflections;
}

Das heißt, dieses Snippet tippt auf das globale Promise (das mit Bluebirds Methoden in bluebird-global.d.ts gepatcht ist). Wie gesagt: Das hier ist zu Ihrer Information, falls Sie es nicht wussten, denn sowohl Ihre als auch meine Snippets funktionieren gleich.

Zurück zum Problem der fehlenden Methoden von Bluebird. Meine Vermutung ist: Sie ersetzen zur Laufzeit nicht global Promise durch Bluebird und führen dann allSettled() mit Promises aus, die mit dem globalen Promise anstelle von Bluebird erstellt wurden.

Lassen Sie mich Ihnen meinen Code und einige Screenshots zeigen.

function allSettled<T>(promises: Array<Promise<T>>) {
    const reflections = Promise.all<T>(promises.map((promise => {
        return promise.reflect();
    })));

    return reflections;
}

let promises = [
    Promise.resolve(),
    Promise.reject(new Error("rejected test")),
    new Promise<void>(() => {}),
];

let reflections = allSettled(promises);

console.log(reflections);
// this is part of my entry point

/*
 * Promise
 */
import * as Promise from 'bluebird';
import 'expose-loader?Promise!bluebird';

image
_Bild 1: Das Versprechen in der Array.map() ist Bluebird (man erkennt es an den Unterstrichen wie: _bitField )_

image
_Bild 2: Promise.reflect ist tatsächlich in der Schleife definiert_

Könnten Sie einen js-Breakpoint wie ich in Chrome Dev Tools setzen und sehen, was promise innerhalb von .map ist? Besser noch: Könnten Sie einfach Promise in die Konsole eingeben und sehen, ob Sie die folgende Ausgabe erhalten:
image

Wenn Sie die folgende Ausgabe erhalten, haben Sie in der Laufzeit NICHT globales Promise durch Bluebird ersetzt:
image

In diesem Fall müssen Sie es tun. ZB like me in deiner Eintragsdatei.

Abschließend noch ein kleines Entwickler-Feedback: Ich persönlich würde Promise<T>[] anstelle von Array<Promise<T>> verwenden. Aber das liegt natürlich an den Vorlieben der Entwickler. Ich komme gerade aus dem C-Hintergrund, wo es keine Vorlagen gibt und wo Entwickler den Array-Zugriffsoperator verwenden, um Typen zu definieren.

Beifall.

Vielen Dank für so eine ausführliche Erklärung. Eine Sache, bei der ich mir nicht sicher war, war, worauf der folgende Punkt hinausläuft:

import 'expose-loader?Promise!bluebird';

@d-ph ahhh, der eine Liner oben war das, was mir gefehlt hat. Ohne deine Hilfe wäre ich niemals dorthin gekommen! Es kann nur an mir liegen, aber ich denke, es wäre hilfreich, wenn der Text README einen Hinweis auf die Verwendung von Expose Loader enthalten würde.

Um fair zu sein, ich bin mir immer noch nicht 100% sicher, ob dies dann die Verwendung von Webpack erfordert? Mein Ziel ist nicht der Browser, nur eine Node-Funktion.

Tatsächlich sieht es so aus, als würde es nicht vollständig funktionieren, da ich die folgende Fehlermeldung erhalte, wenn ich versuche, die Datei auszuführen (keine Fehler im Editor vor der Laufzeit):

Fehler: Modul 'expose-loader?Promise!bluebird' kann nicht gefunden werden

Sie haben Recht, expose-loader ist ein Webpack-Ding (ein Webpack-Loader). Wenn Sie also nicht zulassen, dass webpack diese import -Anweisung verarbeitet, wird sie nicht ausgeführt (dh Sie erhalten den Fehler „Modul kann nicht gefunden werden“).

Wenn Sie Webpack nicht verwenden können/wollen, müssen Sie einen anderen Weg finden, um das globale Versprechen zur Laufzeit zu Bluebird zu machen. Ich habe nicht viel Erfahrung mit Knoten, aber ich habe gerade Folgendes gefunden: https://github.com/petkaantonov/bluebird/issues/1026 (Überschreiben Promise im Knoten).

Ich empfehle herauszufinden, wie man async/await im neuesten Knoten 7 verwendet. Sie haben das Glück, in Zeiten zu leben, in denen dies für Entwickler verfügbar ist.

Was die Verwendung expose-loader in der README betrifft: Ich erkläre bereits oben in der d.ts -Datei, dass dies die Aufgabe der Entwickler ist, Promise zur Laufzeit durch Bluebird zu ersetzen: link . Da es so viele Möglichkeiten gibt, dies zu tun, habe ich keine davon erwähnt. Denken Sie daran, dass expose-loader nur das Äquivalent zum Ausführen von window.Promise = Bluebird ist. Nun, hoffentlich indexiert Google meine Antwort, damit die Leute nicht mehr zu lange nach möglichen Optionen suchen ;p

@d-ph freut sich auf natives async-await, aber all diese Funktionen befinden sich auf AWS Lambda, also bin ich vorerst an Knoten 6.10.x gebunden. In einem zukünftigen Durchgang dieser Funktionen werde ich wahrscheinlich sowieso zu async-await wechseln und es von Typescript nach ES2015 transpilieren lassen, aber das möchte ich jetzt noch nicht vorstellen.

Wie auch immer, danke für den Link @d-ph, ich werde diesen Ansatz ausprobieren. Oh und falls es jemanden interessiert, die endgültige Version dieser Funktionen (die im Land der Verheißung ziemlich praktisch sind):

export function allSettled<T>(promises: Array<Promise<T>>) {
  const reflections = Promise.all<Promise.Inspection<T>>( promises.map((p => p.reflect())) );
  return reflections as Promise<Array<Promise.Inspection<T>>>;
}

export function settleProps<T>(promiseHash: IDictionary<Promise<T>>) {

  const reflections: IDictionary<Promise<Promise.Inspection<T>>> = Object.keys(promiseHash)
    .reduce((newObject: IDictionary<any>, key: string) => {
      newObject[key] = promiseHash[key].reflect();
      return newObject;
    }, {} as IDictionary<Promise<Promise.Inspection<T>>>);

  return Promise.props(reflections) as Promise<IDictionary<Promise.Inspection<T>>>;
}

Vollständige Intelisync/Typ-Informationen sind verfügbar, was super nett ist.

@d-ph hoffentlich ist es in Ordnung, wenn ich das mit einer relevanten Frage wiederbelebe ...

Wenn ich versuche, bluebird-global zu verwenden, scheine ich sowohl in then als auch in catch geringfügige Definitionsunterschiede zu bekommen. Ich sehe, dass diese speziell in bluebird-global behandelt werden, aber es scheint mich auf die Standard-Promise-API zu beschränken, anstatt bluebird zu bekommen. Beispielsweise:

Promise.resolve(true).catch(Error, () => false)

schlägt fehl, da catch nur 1 Argument erwartet.

Und noch ein Problem:

Promise.resolve([3]).map((n: number) => true)

Scheitert mit:

│TS2345: Argument of type '(n: number) => boolean' is not assignable to parameter of type 'IterateFunction<{}, boolean>'.           │
│  Types of parameters 'n' and 'item' are incompatible.                                                                             │
│    Type '{}' is not assignable to type 'number'.                                                                                  │

Sollten die funktionieren oder mache ich etwas falsch? Sie arbeiten zur Laufzeit, sie führen nur keine Typprüfung durch.

Danke!

Hallo,

In Bezug .catch(Error, function) haben Sie Recht, wenn Sie sagen, dass .then , .catch (und mehr) anders gehandhabt werden als die übrigen Bluebird-Funktionen. Die spezifische .catch(Error, function) -Überschreibung ist jedoch in bluebird-global enthalten . Ich habe es noch einmal überprüft und kann Folgendes kompilieren:

Promise.resolve(true).catch(Error, () => false)

Ich habe mit TS 3.0.1 und 2.9.2 nachgesehen. Ich weiß nicht, warum Sie hier auf ein Problem stoßen könnten. Vielleicht gibt es etwas Bestimmtes in Ihrem TS-Projekt, das das globale Versprechen nach bluebird-global außer Kraft setzt. Ich weiß nicht. Versuchen Sie vielleicht, die Ursache des Problems einzugrenzen, indem Sie mit einem sehr einfachen TS-Projekt beginnen und dann weitere Abhängigkeiten von Ihrem aktuellen Projekt hinzufügen, und sehen Sie, an welchem ​​​​Punkt es bricht.

Zum anderen Problem: Ich weiß nicht, warum es nicht funktioniert. Und ja, es sollte funktionieren. Bitte erstellen Sie ein Github-Problem dafür und wir werden von dort aus weitermachen. Hier ein paar Fakten zum Problem:

  1. Alles, was bluebird-global mit .map() macht, ist nur die Wiederverwendung der $ .map() Typdefinition bluebird.d.ts . Mit anderen Worten, der Fehler sollte nicht von den bluebird-global -Typisierungen herrühren.
  2. Die von Ihnen erwähnte Zeile schlägt bei Promise.map() fehl, funktioniert aber bei Bluebird.map() :
import Bluebird = require('bluebird');

Bluebird.resolve([3]).map((n: number) => true); // works

Promise.resolve([3]).map((n: number) => true); // fails
  1. Nachdem ich einige Zeit damit verbracht hatte, das Problem des Typoskripts zu entschlüsseln (im Wesentlichen: warum TS zu dem Schluss kommt, dass der Parameter von n {} sein sollte), kam ich zu dem Schluss, dass bluebird.d.ts auch nicht funktionieren sollte, aber es funktioniert aus mir unbekanntem Grund. Um es kurz zu machen, Folgendes ist das, wofür .map() eingegeben wird, nachdem alle Ebenen von Abstraktionen entfernt wurden:
map<U>(
    mapper: (
        item: U,
        index: number,
        arrayLength: number
    ) => U | PromiseLike<U>,
    options?: Bluebird.ConcurrencyOption
): Bluebird<T extends Iterable<any> ? U[] : never>;

Es besagt, dass der Rückgabetyp der Funktion mapper derselbe (oder ein Versprechen desselben) sein sollte wie der Typ der item . In Ihrem Beispiel ist der Elementtyp number und der Rückgabetyp ist boolean . Ich kann nicht verstehen, warum dies kompiliert wird, wenn Bluebird direkt verwendet wird, aber nicht, wenn das globale Versprechen verwendet wird. Übrigens funktioniert es immer noch nicht, wenn ich den Rückgabetyp in Ihrem Beispiel auf eine beliebige Zahl ändere. Es funktioniert jedoch, wenn ich sage, dass item vom Typ any sein kann. Irgendetwas stimmt mit bluebird.d.ts type IterableItem<R> und seiner Verwendung in diesem Zusammenhang nicht.

@d-ph


Bearbeiten:

Ich habe das "unlayered"-Formular map() erneut überprüft, und die Funktion mapper ist nicht so typisiert, dass sie denselben Rückgabetyp wie der Typ von item hat (ich dachte es war). Mein Fehler.

Alles, was bluebird-global mit .map() macht, ist nur die Wiederverwendung der .map()-Typdefinition von bluebird.d.ts.

Ist das Problem, dass beim Kopieren des Typs aus der generischen Klasse Bluebird<R> standardmäßig {} für R verwendet wird, da er nicht von der übergeordneten Klasse abgeleitet werden kann?

Ich frage mich, ob map: typeof Bluebird<T>.prototype.map funktionieren würde? (das habe ich noch nicht probiert)

WICHTIG:
Wenn Sie @types/bluebird-global verwenden, löschen Sie Ihre Abhängigkeiten @types/bluebird wie von @d-ph gesagt

npm install --save-dev @types/bluebird-global und befolgen Sie dann die Anweisungen, die ich in die Eingaben eingefügt habe: Link (Link aktualisiert am 02.04.2017). Dies allein sollte ausreichen (dh es sollten keine manuellen Importe/Neuzuweisungen erforderlich sein).

Als Nebenbemerkung: Sie müssen @types/bluebird nicht mehr in Ihren package.json::devDependencies erwähnen, da dies automatisch impliziert wird.

Beides verursachte eine fehlende Übereinstimmung zwischen den Typen, die von @types/bluebird zurückgegeben wurden, und meinem globalen Versprechen ( @types/bluebird-global ).

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen