Definitelytyped: bluebird 3.0: ¿cómo usarlo como sobrecarga para Global Promise?

Creado en 24 ago. 2016  ·  44Comentarios  ·  Fuente: DefinitelyTyped/DefinitelyTyped

¡Hola a todos!

Estoy usando bluebird como reemplazo del objeto Promise global. Intenté actualizar typedefs a la última versión, publicada por @lhecker , y me encontré con un problema: global Promsie no está sobrecargado ahora de forma predeterminada.
¿Cómo puedo lograr el comportamiento anterior? ¿Tal vez podríamos tener bluebird-global.d.ts, por ejemplo?

Comentario más útil

Hola tios,

@types/bluebird-global ya está disponible. Estos tipeos usan @types/bluebird@^3.0 debajo del capó y le permiten usar los métodos de bluebird en el Promise global (es decir, la compilación de ts no falla).

Por favor, lea esto para ver cómo usarlo.

Todos 44 comentarios

Bueno, en mi humilde opinión, las definiciones anteriores de Bluebird tampoco fueron una buena solución, porque se filtraron en gran medida en el espacio de nombres global y creo que fue una buena idea reducir los esfuerzos redundantes.

Sin embargo, la forma en que funcionaron las definiciones anteriores es definiendo declare var Promise: PromiseConstructor; mientras que PromiseConstructor era la interfaz Bluebird anterior (definida globalmente).

Es decir, si crea un archivo local *.d.ts y agrega algo como esto, ¿podría funcionar tal vez?

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

¿podría funcionar tal vez?

Lamentablemente no. Porque tengo mucho código, que está escrito así:

declare function doLoadData(): Promise<Data>

como puede ver, la función devuelve Promise<T> , que es Promsie estándar, no bluebird. declarando var Promise: Bluebird<any> sobrecargaré el constructor Promise estándar, no la interfaz.

Cambié de nuevo a los tipos 2.0 por este motivo.

@Strate Ah, maldita sea, escribí un comentario extenso sobre lo que pienso sobre esto y lo que deberíamos tratar de hacer. Pero parece que olvidé enviarlo y finalmente se perdió...

Mucha gente parece tener este problema.

Creé un repositorio que muestra el problema: https://github.com/d-ph/typescript-bluebird-as-global-promise

clonar git && npm install && npm run tsc

El problema:
Los archivos d.ts terceros se escriben contra Promise . Este Promise está definido por lib.es6.d.ts de mecanografiado (cuando "target": "es6" ) o por otras librerías, por ejemplo, core-js (muy popular, cuando se compila a es5 con mecanografiado) . El bluebird.d.ts más reciente no se declara como Promise global, aunque bluebird.js se expone como el Promise global.

Resultado:
Los desarrolladores no pueden usar la funcionalidad de bluebird en las Promesas devueltas por un código de terceros (la compilación falla).

Resultado Esperado:
Los desarrolladores pueden usar la funcionalidad de bluebird en las Promesas devueltas por el código de terceros (la compilación se realiza correctamente).

No estoy seguro de quién es el mantenedor de las tipificaciones de bluebird. @lhecker , eres la persona desafortunada que te devolverá git blame . ¿Podría decirnos cuál es el por qué preferido de usar tipos de bluebird de tal manera que el proyecto github, que vinculé arriba, compile?

Recorridos actuales:

  1. El más sucio. Nunca importe bluebird y nunca use tipos de bluebird. Para funciones bluebird Promise use esto: Promise["config"]({}); Promise.resolve("foo")["finally"](() => { console.log("lol"); }) para silenciar el compilador. Es decir, use el operador de acceso a la matriz: [""]
  2. Sucio y molesto. En cada archivo ts de entrada en su aplicación, agregue estas dos líneas:
import * as Bluebird from 'bluebird';
declare global { export interface Promise<T> extends Bluebird<T> {} }

Para las funciones estáticas de Bluebird, use Bluebird.config({}) en lugar de Promise.config({}) .

La desventaja es que los IDE luchan por interpretar este truco correctamente.

Hmm... Fue un poco imprevisto para mí que ustedes tuvieran problemas con esto, ya que todos están usando Bluebird de una manera que yo y muchos otros no. De hecho, ¡ni siquiera escribí yo mismo las mecanografías! Simplemente copié los únicos existentes para 3.0 desde aquí , porque tener tipeos para 3.0 es mejor que no tener ninguno, ¿verdad?

La cuestión es que la dirección actual a la que se dirige TypeScript es claramente modules > globals que es algo que realmente apruebo. Pero esto también significa que los módulos nunca deberían modificar los objetos globales, ¡especialmente si considera que Bluebird no reemplaza el Promise global en todos los casos! O para decirlo de esa manera:

¿Qué sucede con su "seguridad de tipo" si llama a Promise.noConflict() literalmente en cualquier parte de su código? Revertirá el tipo global Promise al original y hará que su código se bloquee, aunque tsc le dijo que todo está bien.

Así que sí... @d-ph. Su segundo recorrido es lo que debería haber considerado hacer todo el tiempo, ya que está en el espíritu de los sistemas de módulos. Pero sé que esta es solo la solución ideal para las bibliotecas, mientras que _puede_ ser realmente molesto para las aplicaciones. Estoy de acuerdo en que los sistemas de aplicación definitivamente deberían al menos poder reemplazar el objeto global Promise y luego también tener los tipos coincidentes para ese caso de uso, ya que estaba disponible en 2.0.

Al final, creo que, a la luz de la ideología de TypeScript, la extensión del tipo Promise global debe hacerse _muy_ con cuidado (recuerde el problema noConflict() , etc.) y, de ser así, solo como opción.

En mi opinión, el camino a seguir es escribir un archivo bluebird-global.d.ts (o similar) de algún tipo que amplíe el objeto global Promise con las mismas declaraciones de interfaz que se encuentran en el archivo bluebird.d.ts . Y si necesita usarlos, debe importarlos explícitamente en lugar de tenerlos siempre incluidos. De esa manera, puede tener escrituras seguras _y_ correctas para la mayoría de los casos de uso y especialmente al escribir bibliotecas, mientras tiene acceso a los beneficios adicionales de sobrescribir el Promise global en las aplicaciones.

Si crees que esta idea es buena y te queda algo de tiempo libre, sería genial si pudieras crear un PR. Estoy seguro de que muchos estarían muy contentos con tal contribución. 🙂

Lo estoy expresando de esta manera porque actualmente no estoy en la posición de escribir esos tipeos, debido a la falta de tiempo y no necesito tales tipeos en este momento. Espero que puedas entender eso.

@lhecker Creo que podría estar de acuerdo contigo. Porque si tenemos una anulación global de Promise a la de bluebird, solo piratearemos el compilador TypeScript, pero no el mundo real. Por ejemplo, con Promise anulado, el mecanografiado pensará que fetch devuelve el de bluebird:

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

Sin envolver fetch en Promise.resolve $ de bluebird, no obtendrá, por ejemplo, el método .finally en result :

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

Entonces, creo que importar explícitamente bluebird en cada uso es una mejor solución:

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

Voy a refactorizar mi código.

Gracias por tu respuesta, @lhecker .

Estoy de acuerdo con todo lo que dijiste. Y me gusta la solución de @Strate de envolver el código de terceros con el método Promise.resolve() , para transformar la promesa de es6 en la de Bluebird (o la de Bluebird en la de Bluebird, porque quiero mantener la promesa de Bluebird global en el tiempo de ejecución, así que no no necesita confiar en el código de terceros para manejar sus errores correctamente, pero eso no viene al caso).

Parece que no sabía cómo hacer esto correctamente. Lo que creo que otros se beneficiarían es más documentación sobre cómo lidiar con este problema, porque todos los que vienen del mundo de la programación de navegadores (a diferencia de: de nodejs/typescript) lo encuentran después de:

  1. npm install <absolutely everything that uses es6 promise>
  2. npm install bluebird @types/bluebird
  3. use el código de terceros con mecanografiado

También me beneficiaría tener esta sección "Cómo usar en caso de que se escriba un código de terceros contra la Promesa es6" documentada en alguna parte para futuras referencias. es decir, tener la

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

y

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

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

en un archivo Léame o en el bloque de documentos en la parte superior del archivo bluebird.d.ts.

¿Qué piensas?

Completé el cambio de la anulación global de Promise a las de bluebird, y encontré algunos problemas, en los que las bibliotecas de terceros devuelven ES6 Promise, que se antaño como la de bluebird. Entonces, hacer ese movimiento también limpió mi base de código. Recomendaría a todos pasar de la sobrecarga global de Promise . Salud :)

Entiendo modules > globals pero digamos por el bien del argumento (y/o la realidad) que estoy trabajando en un SPA de navegador grande y me han encargado que use Bluebird como nuestro polyfill de Promise.

Estoy probando la solución bluebird-global.d.ts sugerida por @lhecker con el contenido de @d-ph:

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

Lo instalé a través typings que generó mi typings/modules/bluebird-global/index.d.ts :

// 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> {} }
}

Sin embargo, cuando trato de construir todo, TypeScript (v1.8.2) se queja:

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.

Eché un vistazo al ejemplo de MS por global-modifying-module.ts
https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-modifying-module-d-ts.html

Y un problema de TS relacionado con este mensaje de error
https://github.com/Microsoft/TypeScript/issues/6722

Pero no sé qué debería estar haciendo. ¿Alguien puede ayudar?

Hola.

¿Podría consultar mi repositorio, que muestra el problema y la solución? enlace Estaba bastante contento con él, hasta que decidí envolver todas las promesas de terceros en el constructor Promise de bluebird, que es lo que hago ahora. ¿Podría confirmar que después de seguir los pasos en el archivo Léame, no puede compilar, pero después de descomentar el

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

compila?

Tenga en cuenta que mi repositorio usa TS 2 (que ahora es estable) y usted dijo que está usando 1.8.2. Solo verifique lo que sucede cuando actualiza TS a 2.

Finalmente, tuve algunos problemas al poner mi solución en mi archivo global d.ts . Terminé agregándolo a cada punto de entrada de la compilación de mi paquete web, lo que resolvió el problema (lo que ahora tiene sentido para mí). No conozco su configuración js, pero ¿podría intentar poner mi solución en cada archivo que falla durante la compilación (o al menos uno de ellos) y verificar si ayuda?

También quiero poder "registrar" la implementación de Promise de Bluebird como Promise Promise . He leído todo este hilo pero no sigo una parte. La parte que sugiere que las bibliotecas de terceros aún devolverán la implementación nativa (por ejemplo, no Bluebird) Promise . ¿Cómo podría ser esto, cuando ese código de terceros en algún momento invoca el constructor Promise ( new Promise(...) ) que ha sido reemplazado con la implementación de Bluebird a nivel global?

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

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

¿No debería funcionar bien ya que incluí Bluebird, que reemplazó la implementación nativa Promise ?

Finalmente, si estoy haciendo este reemplazo global completo en tiempo de ejecución, debería poder informar a TypeScript sobre esto para que en el momento de la compilación, todas las Promesas también se reemplacen con Bluebird.

¿Qué me estoy perdiendo?

Si usa la versión dist de bluebird (que es lo que hace), las bibliotecas de terceros usarán Bluebird, ya que la Promesa global ahora es Bluebird. Obtienes bien esta parte. La gente menciona lo contrario, porque hablan sobre el uso de Bluebird en node.js.

Todo este hilo trata sobre la forma no tan obvia de hacer que ts se compile con esa suposición (que la Promesa global es Bluebird). Si lograste hacerlo (por ejemplo, a través de declare global {} ), entonces ya terminaste.

@d-ph Pero mi conclusión es que tengo que hacer eso en cada archivo *.ts en lugar de solo una vez, ¿es correcto? Tal vez sería bueno un resumen de la "solución" final a este problema. :)

Sí, verá, no hay una solución simple just copy&paste this line to your X file and everyone and their dog are happy now aquí. O al menos yo no soy consciente de ello.

La última vez que te revisé, ya sea:

  1. copie y pegue la línea import * as Bluebird from 'bluebird'; declare global { export interface Promise<T> extends Bluebird<T> {} } en cada punto de entrada del archivo *.ts, o
  2. envuelva cada promesa devuelta por un código de terceros en la función constructora de Bluebird. En el tiempo de ejecución no hará nada (excepto por la sobrecarga innecesaria del tiempo de ejecución) y en el tiempo de compilación hará feliz a TS.

Una vez más, la solución 1 requiere poner ese código solo en los archivos de punto de entrada, no en todos los archivos. Al menos, esto es lo que funcionó para mí (webpack + asombroso-mecanografiado-cargador).

Si encuentra otra solución, que literalmente requiera que los desarrolladores coloquen solo 1 línea en 1 archivo, entonces compártala con la comunidad ;p

Gracias @d-ph. ¿Puede confirmar lo que quiere decir con "todos los archivos de punto de entrada * .ts"?

Sí. El archivo .ts "Punto de entrada" es el archivo .ts, que carga en su html a través de la etiqueta <script> . En otras palabras, este es el archivo desde el que comienza la compilación.

Después de buscar en Google rápidamente, encontré esto (no te molestes en leerlo). La conclusión es que si agrega manualmente global { export interface Promise<T> extends Bluebird<T> {} } en bluebird.d.ts, entonces no necesita mencionar esto nuevamente en ningún otro lugar. No tengo tiempo para probarlo en este momento, pero lo probé con el repositorio de prueba de github que creé, y parece funcionar.

En otras palabras, descargue bluebird.d.ts y cambie esto:

// 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> {

a esto:

// 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> {

Obviamente, esto no es ideal, especialmente si usa @types/bluebird (que necesitaría eliminar ahora, porque usaría su bluebird.d.ts pirateado personalizado), pero bueno...

Así que ya tengo un archivo _stubs.d.ts al que agregué lo siguiente, y estoy mucho más cerca. No más quejas sobre finally que no existen en Promise , pero por alguna razón, sigo recibiendo errores sobre delay que no existen en Promise . No tuve que editar bluebird.d.ts . ¡Se investigará, pero esta puede ser una gran solución!

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

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

Editar: mi problema con delay fue porque lo estaba llamando estáticamente, por ejemplo, Promise.delay(2000) .

Con la solución que publiqué anteriormente, recibo este error cuando mi función devuelve Promise<T> :

error TS2322: Escriba 'Bluebird' no se puede asignar al tipo 'Promesa'.

Supongo que esto se debe a que ahora que he reemplazado Promise con Bluebird , cada vez que uso then , etc., el valor de retorno es Bluebird<T> en su lugar de Promise<T> .

Aquí está mi versión final de este truco. No me gusta hacer esto, pero me gusta más que las otras opciones. Básicamente, tengo que reiterar las cosas que estoy usando en la interfaz, cambiando el tipo de retorno a Promise en lugar de Bluebird . Esta es una copia y pegado directo del archivo de definición de Bluebird aparte de eso.

_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>;
        }
    }
}

Sería genial tener una definición oficial bluebird-global o bluebird-override que se parezca mucho a la definición existente pero use Promise en todas partes en lugar de Bluebird .

Me alegro de que hayas podido encontrar una solución.

Solo para completar: como dijo @ProTip , usando bluebird-2.0.d.ts JustWorksTM. Simplemente instálelo con npm install @types/[email protected] y agréguelo a compilerOptions.types de tsconfig.json:

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

Cualquier diferencia entre ese .d.ts y la versión actual de Bluebird (es decir, 3.x) recomiendo piratear manualmente.

Por JustWorksTM quiero decir: funciona para:

a) objetivo es5
b) objetivo es6
c) objetivo es5 con core-js lib

independientemente de si alguien usa una configuración de compilación (paquete web + asombroso-cargador-mecanografiado) o no. Además, PhpStorm IDE no se confunde en absoluto.

Pasé un tiempo hoy analizando este problema y, de hecho, creé/actualicé esos dos boletos en Microsoft/TypeScript: https://github.com/Microsoft/TypeScript/issues/10178 y https://github.com/Microsoft/TypeScript /temas/12382 . Mi idea es, como dijiste (y algunos antes que tú), que necesitamos un archivo bluebird-global.d.ts . Para evitar el código duplicado, descubrí que esto funcionaría:

// bluebird-global.d.ts

import * as Bluebird from "bluebird";

export as namespace Promise;
export = Bluebird;

siempre que se resuelvan los dos tickets antes mencionados o se encuentren soluciones alternativas. Mientras tanto, recomiendo usar bluebird-2.0.d.ts cuando codifique para el navegador.

@JoshMcCullough

¿Cómo podría ser esto, cuando ese código de terceros en algún momento invoca el constructor de Promise (new Promise (...)) que ha sido reemplazado con la implementación de Bliebird a nivel global?

Muy fácil. Pruebe en la consola de su navegador (preferiblemente 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!

Hola. He estado haciendo esto y es bastante suave. En primer lugar, no dependa de bluebird para proyectos de biblioteca. Para el proyecto de la aplicación, importe bluebird pero no las escrituras. En el punto de entrada de su aplicación, haga esto:

global['Promesa'] = require('pájaro azul')

Esto reemplazará el objeto de promesa global para la aplicación y todas las bibliotecas incluidas.

Hola tios,

@types/bluebird-global ya está disponible. Estos tipeos usan @types/bluebird@^3.0 debajo del capó y le permiten usar los métodos de bluebird en el Promise global (es decir, la compilación de ts no falla).

Por favor, lea esto para ver cómo usarlo.

Impresionante, gracias @d-ph!

@d-ph Gracias por el @types/bluebird-global . ¿Necesito hacer algún tipo de importación y reasignación en mi proyecto para usar bluebird como reemplazo de la Promesa global?

npm install --save-dev @types/bluebird-global y luego siga las instrucciones que incluí en las escrituras: enlace (enlace actualizado 2017-04-02). Esto por sí solo debería ser suficiente (es decir, no deberían ser necesarias importaciones/reasignaciones manuales).

Como nota al margen: ya no necesita mencionar @types/bluebird en su package.json::devDependencies , porque esto está implícito automáticamente.

Actualizar al enlace en el comentario anterior: enlace

@MichaelTontchev @d-ph ¿hay alguna posibilidad de que podamos agregar la interfaz Promise.Inspection a bluebird-global ?

Hola @ksnyde.

Por favor habla conmigo. Soy el mantenedor.

¿Podría confirmar que se refiere a esta Promesa . Inspección, por favor?

Todos los métodos de esa interfaz se exponen a través bluebird-global . Es decir, se compilará lo siguiente:

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

Entonces me parece que está solicitando que esto se exponga como Promise.Inspection de bluebird-global .

¿Podría decirme si esto es un gran revés para usted para usar lo siguiente en su lugar:

import * as Bluebird from "bluebird";

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

}

Dado que está utilizando bluebird-global , también puede importar los tipeos originales bluebird así sin ningún devDependencies explícito.

Preferiría no extender más el Promise global sin razones sólidas detrás de él, porque es un arte sutil hacer que esas escrituras funcionen con las escrituras estándar de Promise de lib.d.ts . Realmente recomiendo acceder a esta interfaz directamente desde bluebird , porque algún día los gurús de JavaScript podrían agregar Promise.Inspection al estándar, lo que rompería los bluebird-global , lo que en consecuencia causar problemas innecesarios a los usuarios finales.

Además, incluso si tuviera que agregar la interfaz, tendría que esperar una cantidad de tiempo no especificada para que se fusione con master , porque los mantenedores de DT están un poco ocupados con las relaciones públicas en estos días.

Salud.

De hecho, he estado usando el enfoque que discutió por el momento y es un trabajo adecuado. O tal vez "trabajar en torno a" es la nomenclatura incorrecta.

Entendí/percibí que la idea detrás de bluebird-global era exponer el superconjunto de la funcionalidad Promise que proporciona bluebird, en cuyo caso, como usuario, _esperaría_ que Bluebird.Inspection se expusiera en Promise.Inspection . Sin embargo, si su intención es simplemente asegurarse de que la superficie API oficial de Promises use Bluebird, entonces supongo que esta "solución alternativa" es en realidad una solución adecuada a largo plazo.

Si bien prefiero mi interpretación, estaré bien usando la solución presentada aquí si es necesario.

Aunque ciertamente veo de dónde viene con sus expectativas, la razón principal por la que creé bluebird-global fue para que TypeScript supiera que las promesas creadas y devueltas por código de terceros son en realidad instancias de promesas de Bluebird, a las que no había otra alternativa _no molesta_, sino exponer todas las instancias de Bluebird y los métodos estáticos en el símbolo de Promesa global. Como mencioné anteriormente, la forma en que se hace no es un simple class Promise<T> extends Bluebird<T> {} (aunque originalmente lo era), sino más bien un símbolo de Promesa global cuidadosamente parchado. Y como mencioné, prefiero evitar tener que mantener nada, para lo cual existe una alternativa conocida, que literalmente no te hace arrancarte los pelos de la cabeza.

Lo siento por decir "No" a este. Si hay más personas que solicitan esta función en particular, reconsideraré agregarla. No quiero sonar autoritario aquí: este es un proyecto de código abierto y cualquiera podría probablemente incluir esta función. El punto que estoy tratando de transmitir aquí es que, en mi opinión, el beneficio de tener esto no compense el costo de mantenerlo.

Salud.

tiene sentido. gracias por el pensamiento detrás de su enfoque.

@d-ph, ¿tiene sentido lo siguiente para usted? Recibo un error que indica que "reflejar" no es una función en el siguiente código:

image

Y mientras que en la inteligencia del editor se identifica correctamente que la propiedad p en la función de mapeo es una promesa de Bluebird y tiene la superficie API extendida que solo se encuentra en Bluebird (frente a Promise).

image

Simplemente no puedo sacarle cara o cruz. Me di cuenta de que cuando inspecciono el _tipo_ de la variable del iterador del mapa, aparece como:

image

Supuse que, en última instancia, esta es la razón por la que obtengo la superficie API limitada definida por bluebird-global pero no sé por qué no se resuelve correctamente.

Hola.

No puedo reproducir:/ Esos fragmentos de código funcionan en mi configuración.

Ante todo. no está usando bluebird-global en su función allSettled() . Escribes directamente usando Bluebird . Esto no es un problema, pero tal vez no lo sabías. El siguiente fragmento usa bluebird-global :

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

    return reflections;
}

Es decir, ese fragmento se escribe en el Promise global (que está parcheado con los métodos de Bluebird en bluebird-global.d.ts ). Como dije: este es para su información, en caso de que no lo supiera, porque tanto sus fragmentos como los míos funcionan de la misma manera.

Volvamos al problema de perder los métodos de Bluebird. Mi conjetura es: no reemplaza global Promise con Bluebird en tiempo de ejecución y luego ejecuta allSettled() con Promises construido usando Global Promise en lugar de Bluebird.

Déjame mostrarte mi código y algunas capturas de pantalla.

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
_Imagen 1: La promesa en Array.map() es Bluebird (se nota por la presencia de las propiedades de subrayado como: _bitField )_

image
_Imagen 2: Promise.reflect está definido en el bucle_

¿Podría establecer un punto de interrupción js como yo en Chrome Dev Tools y ver qué es el promise dentro del .map ? Mejor aún: ¿podría simplemente escribir Promise en la consola y ver si obtiene el siguiente resultado?
image

Si obtiene el siguiente resultado, entonces NO reemplazó Global Promise con Bluebird en tiempo de ejecución:
image

En cuyo caso tienes que hacerlo. Por ejemplo, como yo en su archivo de entrada.

Finalmente, solo un poco de comentarios de los desarrolladores: personalmente usaría Promise<T>[] en lugar de Array<Promise<T>> . Pero esto depende de la preferencia de los desarrolladores, por supuesto. Solo vengo del fondo C, donde no hay plantillas y donde los desarrolladores usan el operador de acceso a la matriz para definir tipos.

Salud.

Muchas gracias por una explicación tan completa. Sin embargo, una cosa de la que no estaba seguro era a qué apunta lo siguiente:

import 'expose-loader?Promise!bluebird';

@d-ph ahhh, el delineador de arriba era lo que me faltaba. ¡Nunca hubiera llegado allí sin su ayuda! Puede que solo sea yo, pero creo que sería útil si el texto README tuviera una referencia al uso de Expose Loader .

Aunque para ser justos, todavía no estoy al 100% si esto requiere el uso de un paquete web. Mi objetivo no es el navegador, solo una función de nodo.

De hecho, parece que no funciona del todo, ya que recibo el siguiente error cuando intento ejecutar el archivo (no hay errores en el editor antes del tiempo de ejecución):

Error: No se puede encontrar el módulo 'expose-loader?Promise!bluebird'

Tienes razón, expose-loader es una cosa de paquete web (un cargador de paquete web). Entonces, si no permite que webpack procese esa instrucción import , no se ejecutará (es decir, obtendrá el error "No se puede encontrar el módulo").

Si no puede/no usa el paquete web, deberá encontrar otra forma de hacer que la Promesa global sea Bluebird en tiempo de ejecución. No tengo mucha experiencia con el nodo, pero encontré esto ahora: https://github.com/petkaantonov/bluebird/issues/1026 (anulando Promise en el nodo).

Recomiendo descubrir cómo usar async/await en el último nodo 7. Tienes la suerte de vivir en una época en la que está disponible para los desarrolladores.

En cuanto a mencionar el uso expose-loader en el LÉAME: ya indiqué en la parte superior del archivo d.ts , que este es el trabajo de los desarrolladores para reemplazar Promise con Bluebird en tiempo de ejecución: enlace . Como hay tantas formas de hacerlo, en realidad no mencioné ninguna de ellas. Tenga en cuenta que expose-loader es solo el equivalente de ejecutar window.Promise = Bluebird . Bueno, espero que Google indexe mi respuesta, para que la gente ya no busque posibles opciones por mucho tiempo ;p

@d-ph espero con ansias la espera asincrónica nativa, pero todas estas funciones están en AWS Lambda, por lo que estoy bloqueado en el nodo 6.10.x por ahora. En un paso futuro de estas funciones, probablemente cambiaré a async-await de todos modos y haré que Typescript transpile a ES2015, pero no quiero presentar esto todavía.

De todos modos, gracias por el enlace @d-ph, probaré ese enfoque. Ah, y en caso de que alguien esté interesado, la versión final de estas funciones (que son bastante útiles en la tierra prometida):

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>>>;
}

La información completa de intelisync/type está disponible, lo cual es muy agradable.

@d-ph espero que esté bien si revivo esto con una pregunta relevante...

Cuando intento usar bluebird-global, parece que obtengo diferencias por definición tanto en then como catch . Veo que se manejan especialmente en bluebird-global, pero parece limitarme a la API estándar de Promise en lugar de obtener bluebird. Por ejemplo:

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

falla como catch solo espera 1 argumento.

Y otro tema:

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

falla con:

│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'.                                                                                  │

¿Deberían funcionar o estoy haciendo algo mal? Trabajan en tiempo de ejecución, simplemente no verifican el tipo.

¡Gracias!

Hola,

Acerca de .catch(Error, function) , tiene razón al decir que .then , .catch (y más) se manejan de manera diferente que el resto de las funciones de Bluebird. Sin embargo, la anulación específica .catch(Error, function) está incluida en bluebird-global . Verifiqué dos veces y puedo compilar:

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

Verifiqué con TS 3.0.1 y 2.9.2. No sé por qué podrías estar teniendo un problema aquí. Tal vez haya algo específico en su proyecto de TS que invalide la Promesa global después bluebird-global . No sé. Tal vez intente reducir lo que está causando el problema comenzando con un proyecto TS muy básico y luego agregando más dependencias de su proyecto actual, y vea en qué punto se rompe.

Sobre el otro problema: no sé por qué no funciona. Y sí, debería funcionar. Cree un problema de github para ello y partiremos de allí. Aquí hay algunos datos sobre el problema:

  1. Todo lo que bluebird-global hace con .map() es simplemente reutilizar la definición de tipo bluebird.d.ts de .map() . En otras palabras, el defecto no debería provenir de las tipificaciones bluebird-global .
  2. La línea que mencionaste falla en Promise.map() , pero funciona en Bluebird.map() :
import Bluebird = require('bluebird');

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

Promise.resolve([3]).map((n: number) => true); // fails
  1. Después de dedicar algún tiempo a descifrar el problema del mecanografiado (esencialmente: por qué TS concluye que el parámetro de n debería ser {} ), llegué a la conclusión de que bluebird.d.ts tampoco debería funcionar, pero funciona por razones desconocidas para mí. Para resumir, lo siguiente es lo que se escribe .map() después de eliminar todas las capas de abstracciones:
map<U>(
    mapper: (
        item: U,
        index: number,
        arrayLength: number
    ) => U | PromiseLike<U>,
    options?: Bluebird.ConcurrencyOption
): Bluebird<T extends Iterable<any> ? U[] : never>;

Dice que el tipo de devolución de la función mapper debe ser el mismo (o una Promesa de lo mismo) que el tipo de item . En su ejemplo, el tipo de artículo es number y el tipo de devolución es boolean . No puedo comprender por qué esto se compila cuando se usa Bluebird directamente, pero no cuando se usa la Promesa global. Por cierto, todavía no funciona, cuando cambio el tipo de devolución en su ejemplo para que sea cualquier número. Sin embargo, funciona cuando digo que el item puede ser del tipo any . Hay algo mal con bluebird.d.ts type IterableItem<R> y su uso en este contexto.

@d-ph


Editar:

Revisé el formulario "sin capas" map() nuevamente, y la función mapper no está escrita para tener el mismo tipo de retorno que el tipo de item (pensé que era). Mi error.

Todo lo que bluebird-global hace con .map() es simplemente reutilizar la definición de tipo .map() de bluebird.d.ts.

¿El problema es que cuando copia el tipo de la clase genérica Bluebird<R> , el valor predeterminado es {} para R ya que no puede inferirlo del padre?

Me pregunto si map: typeof Bluebird<T>.prototype.map funcionaría. (No he probado esto todavía)

IMPORTANTE:
Si usa @types/bluebird-global , elimine sus dependencias @types/bluebird como dijo @d-ph

npm install --save-dev @types/bluebird-global y luego siga las instrucciones que incluí en las escrituras: enlace (enlace actualizado 2017-04-02). Esto por sí solo debería ser suficiente (es decir, no deberían ser necesarias importaciones/reasignaciones manuales).

Como nota al margen: ya no necesita mencionar @types/bluebird en su package.json::devDependencies , porque esto está implícito automáticamente.

Tener ambos estaba causando una falta de coincidencia entre los tipos devueltos por @types/bluebird y mi Promesa global ( @types/bluebird-global )

¿Fue útil esta página
0 / 5 - 0 calificaciones