Definitelytyped: bluebird 3.0:如何将其用作全局 Promise 的重载?

创建于 2016-08-24  ·  44评论  ·  资料来源: DefinitelyTyped/DefinitelyTyped

嘿大家!

我正在使用 bluebird 作为全局 Promise 对象的替代品。 我试图将 typedefs 更新到由@lhecker发布的最新版本,但遇到了问题:默认情况下,全局Promsie现在没有重载。
我如何实现以前的行为? 例如,也许我们可以拥有 bluebird-global.d.ts?

最有用的评论

嗨,大家好,

@types/bluebird-global现在可用。 这些类型在引擎盖下使用@types/bluebird@^3.0并允许您在全局Promise上使用 bluebird 的方法(即 ts 编译不会失败)。

请阅读本文以了解如何使用它。

所有44条评论

恕我直言,以前的 Bluebird 定义也不是一个好的解决方案,因为它们严重泄漏到全局命名空间中,我认为减少冗余工作是个好主意。

之前定义的工作方式是定义declare var Promise: PromiseConstructor;PromiseConstructor是之前的(全局定义的)Bluebird 接口。

即,如果您创建一个本地*.d.ts文件并添加类似这样的内容,它可能会起作用吗?

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

它可能会起作用吗?

抱歉不行。 因为我有很多代码,写成这样:

declare function doLoadData(): Promise<Data>

如您所见,函数返回Promise<T> ,这是标准的Promsie ,而不是蓝鸟。 声明var Promise: Bluebird<any>我将重载标准 Promise 构造函数,而不是接口。

出于这个原因,我切换回了 2.0 类型。

@Strate啊该死的我写了一篇关于我对此的看法以及我们应该尝试做什么的长篇评论。 但是好像忘记提交了,最后丢了……

很多人似乎都有这个问题。

我创建了一个显示问题的存储库: https ://github.com/d-ph/typescript-bluebird-as-global-promise

git 克隆 && npm install && npm run tsc

问题:
第 3 方d.ts文件是针对Promise键入的。 这Promise由 typescript 的lib.es6.d.ts (当"target": "es6"时)或其他库定义,例如core-js (非常流行,当使用 typescript 编译到 es5 时) . 最新的bluebird.d.ts未声明为全局Promise ,即使 bluebird.js 将自身暴露为全局Promise

结果:
开发人员无法在从 3rd 方代码返回的 Promise 上使用 bluebird 的功能(编译失败)。

预期结果:
开发人员可以在从 3rd 方代码返回的 Promises 上使用 bluebird 的功能(编译成功)。

我不确定谁是蓝鸟类型的维护者。 @lhecker ,你是被git blame退回的倒霉人。 你能告诉我们,以这种方式使用蓝鸟类型的首选原因是什么,我在上面链接的 github 项目可以编译?

当前走位:

  1. 最脏的。 永远不要导入 bluebird,永远不要使用 bluebird 类型。 对于 bluebird Promise函数,请使用: Promise["config"]({}); Promise.resolve("foo")["finally"](() => { console.log("lol"); })使编译器静音。 即使用数组访问运算符: [""]
  2. 又脏又烦。 在应用程序的每个条目 ts 文件中添加以下两行:
import * as Bluebird from 'bluebird';
declare global { export interface Promise<T> extends Bluebird<T> {} }

对于 Bluebird 的静态函数,使用Bluebird.config({})而不是Promise.config({})

不利的一面是,IDE 很难正确解释这个 hack。

嗯……我有点没想到你们会遇到这个问题,因为你们都在以我和其他许多人没有的方式使用 Bluebird。 事实上,我什至没有自己写打字! 我只是从这里复制了 3.0 唯一现有的,因为有 3.0 的任何类型总比没有好,对吧?

问题是 TypeScript 的当前方向显然是modules > globals ,这是我真正赞同的。 但这也意味着模块不应该修改全局对象,特别是如果您认为Bluebird不会在每种情况下替换全局Promise ! 或者这样说:

如果您在代码中的任何位置直接调用Promise.noConflict() ,您的“类型安全”会发生什么? 它会将全局Promise类型恢复为原始类型并使您的代码崩溃,即使tsc告诉您一切都很好。

所以是的...@d-ph。 您的第二个解决方案是您应该一直考虑做的事情,因为它本着模块系统的精神。 但我知道这只是库的理想解决方案,而它_可能_对于应用程序来说真的很烦人。 我同意应用程序系统至少应该能够替换全局Promise对象,然后还具有该用例的匹配类型,因为它在 2.0 中可用。

最后,我认为根据 TypeScript 的意识形态扩展全球Promise类型应该_非常_小心地完成(记住noConflict()问题等),如果这样做只是作为选择加入。

IMO 前进的方法是编写某种类型的bluebird-global.d.ts (或类似)文件,该文件使用bluebird.d.ts文件中的相同接口声明扩展全局Promise对象。 如果你需要使用那些你应该明确地导入它们而不是总是包含它们。 这样,您就可以在大多数用例中,尤其是在编写库时,拥有安全的_和_正确的类型,同时还可以获得在应用程序中覆盖全局Promise的额外好处。

如果您认为这个想法很好,并且您还有一些空闲时间,那么如果您可以创建一个 PR,那就太酷了。 我相信很多人会对这样的贡献感到非常高兴。 🙂

我之所以这样说是因为我目前无法编写这些类型,因为时间不够并且目前不需要这样的类型。 我希望你能理解。

@lhecker我想我可以同意你的看法。 因为如果我们对蓝鸟的 Promise 进行全局覆盖,我们只会破解 typescript 编译器,而不会破解现实世界。 例如,重写Promise打字稿会认为fetch返回蓝鸟的一个:

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

如果不将fetch包装到 bluebird 的Promise.resolve ,您将不会获得例如 result 上的result .finally方法:

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

所以,我认为在每次使用时显式导入bluebird是更好的解决方案:

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

我要重构我的代码。

感谢您的回答, @lhecker

我同意你所说的一切。 而且我喜欢@Strate使用Promise.resolve()方法包装 3rd 方代码的解决方案,将 es6 承诺转换为 Bluebird(或 Bluebird 到 Bluebird,因为我想在运行时保持 Bluebird 的承诺全局,所以我不不需要依靠 3rd 方代码来正确处理他们的错误,但这不是重点)。

看起来我不知道如何正确地做到这一点。 我认为其他人会从中受益的是更多关于如何处理这个问题的文档,因为来自浏览器编程世界的每个人(而不是:来自 nodejs/typescript)在他们之后点击它:

  1. npm install <absolutely everything that uses es6 promise>
  2. npm install bluebird @types/bluebird
  3. 使用带有 typescript 的 3rd 方代码

我还将受益于在某处记录此“如何在针对 es6 Promise 键入第 3 方代码的情况下使用”部分以供将来参考。 即拥有

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

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

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

在自述文件或 bluebird.d.ts 文件顶部的 doc 块中。

你怎么认为?

我已经完成了从Promise的全局覆盖到 bluebird 的迁移,并且我发现了一些问题,其中 3rd 方库返回 ES6 Promise,它被视为 bluebird 的。 因此,采取这一举措也清理了我的代码库。 我建议大家从Promise的全局重载中转移。 干杯:)

我理解modules > globals但是为了争论(和/或现实),我正在开发一个大型浏览器 SPA,并且我的任务是使用 Bluebird 作为我们的 Promise polyfill。

我正在尝试@lhecker建议的bluebird-global.d.ts修复,其中包含来自@d-ph 的内容:

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

我已经通过typings安装了它,它生成了我的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> {} }
}

但是,当我尝试构建所有内容时,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.

我查看了global-modifying-module.ts的 MS 示例
https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-modifying-module-d-ts.html

以及与此错误消息相关的 TS 问题
https://github.com/Microsoft/TypeScript/issues/6722

但我不知道我应该做什么。 任何人都可以帮忙吗?

你好。

你能检查我的回购,它显示了问题和解决方案吗? 链接。 我对此非常满意,直到我决定将来自 3rd 方的所有承诺包装到 bluebird 的 Promise 构造函数中,这就是我现在所做的。 您能否确认,按照自述文件中的步骤操作后,您无法编译,但在取消注释后

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

它编译?

请记住,我的仓库使用 TS 2(现在已经稳定),而您说您使用的是 1.8.2。 只需检查将 TS 升级到 2 时会发生什么。

最后,我在将解决方案放入全局d.ts文件时遇到了一些问题。 我最终将它添加到我的 webpack 编译的每个入口点,这解决了问题(现在这对我来说很有意义)。 我不知道您的 js 设置,但是您能否尝试将我的修复程序放在每个文件中,在编译期间失败(或至少其中一个文件)并检查它是否有帮助?

我还希望能够将 Bluebird 的Promise实现“注册”为全局Promise 。 我阅读了整个线程,但我没有遵循其中的一部分。 建议第 3 方库仍将返回本机(例如非 Bluebird) Promise实现的部分。 当第 3 方代码在某个时候调用Promise构造函数( new Promise(...) )时,这怎么可能呢?

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

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

既然我已经包含了取代原生Promise实现的 Bluebird,这难道不应该正常工作吗?

最后,如果我在运行时进行完全的全局替换,我应该能够通知 TypeScript,这样在编译时,所有的 Promises 也会被 Bluebird 替换。

我错过了什么?

如果您使用 bluebird 的 dist 版本(您这样做),那么 3rd 方库将使用 Bluebird,因为全局 Promise 现在是 Bluebird。 你做对了这部分。 人们另有提及,因为他们谈论的是 Bluebird 的 node.js 用法。

整个线程都是关于使 ts 在该假设下编译的不太明显的方式(全局 Promise 是 Bluebird)。 如果你设法做到了(例如通过declare global {}事情),那么你就完成了。

@d-ph 但我的收获是,我必须在每个*.ts文件中执行此操作,而不仅仅是一次——对吗? 也许对这个问题的最终“解决方案”的总结会很好。 :)

是的,你看,这里没有简单的just copy&paste this line to your X file and everyone and their dog are happy now类型的解决方案。 或者至少我不知道。

我最后一次检查你:

  1. import * as Bluebird from 'bluebird'; declare global { export interface Promise<T> extends Bluebird<T> {} }行复制并粘贴到每个入口点*.ts 文件,或
  2. 将从第 3 方代码返回的每个承诺包装在 Bluebird 的构造函数中。 在运行时它什么也不做(除了不必要的运行时开销),在编译时它会让 TS 高兴。

同样,解决方案 1. 只需要将该代码放在入口点文件中,而不是每个文件中。 至少,这对我有用(webpack + awesome-typescript-loader)。

如果您找到另一种解决方案,实际上要求开发人员在 1 个文件中只放入 1 行,那么请与社区分享;p

谢谢@d-ph——你能确认“每个入口点 *.ts 文件”是什么意思吗?

是的。 “入口点” .ts 文件是 .ts 文件,您可以通过<script>标签在 html 中加载该文件。 换句话说,这是编译开始的文件。

经过刚才的快速谷歌搜索,我发现了这个(不要费心阅读它)。 底线是,如果您在 bluebird.d.ts 中手动添加global { export interface Promise<T> extends Bluebird<T> {} } ,那么您无需在其他任何地方再次提及这一点。 我现在没有时间测试它,但我确实使用我创建的测试 github 存储库对其进行了测试,它似乎有效。

换句话说,下载 bluebird.d.ts 并更改:

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

对此:

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

显然这并不理想,特别是如果您使用@types/bluebird (您现在需要删除它,因为您将使用您的自定义黑客 bluebird.d.ts),但是...

所以我已经有一个_stubs.d.ts文件,我在其中添加了以下内容,而且我更接近了。 没有更多关于 Promise 上不存在Promise finally的投诉,但由于某种原因,我仍然收到有关delay上不存在Promise的错误。 我不必编辑bluebird.d.ts 。 将进行调查,但这可能是一个很好的解决方案!

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

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

编辑:我对delay的问题是因为我是静态调用它,例如Promise.delay(2000)

使用我上面发布的解决方案,当我的函数返回Promise<T>时出现此错误:

错误 TS2322:输入“蓝鸟”' 不可分配给类型 'Promise'。

我想这是因为现在我已经用Promise Bluebird ,每当我使用then等时,返回值都是Bluebird<T> Promise<T>

这是我对这个 hack 的最终版本。 我不喜欢这样做,但我比其他选项更喜欢它。 基本上,我必须重新迭代我在界面上使用的东西,将返回类型更改为Promise而不是Bluebird 。 这是 Bluebird 定义文件的直接复制和粘贴。

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

最好有一个官方的bluebird-globalbluebird-override定义,它看起来很像现有的定义,但在任何地方都使用Promise而不是Bluebird

很高兴您能够找到解决方案。

只是为了完整性:正如@ProTip所说,使用bluebird-2.0.d.ts JustWorksTM。 只需使用npm install @types/[email protected]安装它并将其添加到 tsconfig.json 的compilerOptions.types

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

我建议手动破解该 .d.ts 和当前 Bluebird 版本(即 3.x)之间的任何差异。

JustWorksTM 我的意思是:它适用于:

a) es5 目标
b) es6 目标
c) 带有 core-js 库的 es5 目标

无论是否有人使用构建设置(webpack + awesome-typescript-loader)。 此外,PhpStorm IDE 一点也不混乱。

我今天花了一些时间研究这个问题,实际上在 Microsoft/TypeScript 中创建/更新了这两张票: https ://github.com/Microsoft/TypeScript/issues/10178 和https://github.com/Microsoft/TypeScript /问题/12382 。 我的想法是,正如您所说(以及您之前所说的),我们需要一个bluebird-global.d.ts文件。 为了避免重复的代码,我发现这会起作用:

// bluebird-global.d.ts

import * as Bluebird from "bluebird";

export as namespace Promise;
export = Bluebird;

前提是解决了上述两个问题或找到了解决方法。 同时,我建议在为浏览器编码时使用 bluebird-2.0.d.ts。

@JoshMcCullough

当第 3 方代码在某个时候调用已被全局级别的 Bliebird 实现替换的 Promise 构造函数 (new Promise(...)) 时,这怎么可能?

相当容易。 在浏览器的控制台中尝试(首选 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!

你好。 我一直在这样做,而且非常顺利。 首先,图书馆项目不要依赖蓝鸟。 对于应用程序项目,导入 bluebird 但不导入类型。 在应用程序的入口点,执行以下操作:

全球['承诺'] = 要求('蓝鸟')

这将替换应用程序的全局承诺对象和所有包含的库。

嗨,大家好,

@types/bluebird-global现在可用。 这些类型在引擎盖下使用@types/bluebird@^3.0并允许您在全局Promise上使用 bluebird 的方法(即 ts 编译不会失败)。

请阅读本文以了解如何使用它。

太棒了,谢谢@d-ph!

@d-ph 感谢您的@types/bluebird-global 。 我是否需要在我的项目中进行任何类型的导入和重新分配以使用 bluebird 作为全局 Promise 的替代品?

npm install --save-dev @types/bluebird-global然后按照我在打字中包含的说明进行操作:链接(链接更新于 2017-04-02)。 仅此一项就可以解决问题(即不需要手动导入/重新分配)。

作为旁注:您不再需要在package.json::devDependencies #$ 中提及@types/bluebird ,因为这是自动暗示的。

更新到上一条评论中的链接: link

@MichaelTontchev @d-ph 我们有没有机会将Promise.Inspection接口添加到bluebird-global

嗨@ksnyde。

请跟我说话。 我是维护者。

你能确认一下,你指的是这个 Promise.Inspection吗?

该接口的所有方法都通过bluebird-global公开。 即以下将编译:

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

所以在我看来,您要求其公开为Promise.Inspection中的bluebird-global

您能否告诉我,这是否是您使用以下内容的重大挫折:

import * as Bluebird from "bluebird";

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

}

由于您使用的是bluebird-global ,因此您还可以像这样导入原始的bluebird类型,而无需任何明确的devDependencies

如果没有充分的理由,我宁愿不要进一步扩展全局Promise ,因为让这些类型与来自lib.d.ts的标准 Promise 类型一起工作是一种微妙的艺术。 我真的建议直接从bluebird类型中访问这个接口,因为有一天 JavaScript 专家可能会将Promise.Inspection添加到标准中,这会破坏bluebird-global类型,结果会给终端用户带来不必要的麻烦。

此外,即使我要添加接口,您也需要等待未指定的时间才能将其合并到master ,因为这些天 DT 的维护人员有点忙于 PR。

干杯。

我确实一直在使用你讨论的方法,这是一个足够的解决方法。 或者也许“变通”是错误的命名法。

我的理解/理解是 bluebird-global 背后的想法是公开 bluebird 提供的 Promise 功能的超集,在这种情况下,作为用户,我_would_ 期望Bluebird.InspectionPromise.Inspection公开。 但是,如果您的意图只是确保 Promises 的官方 API 表面使用 Bluebird,那么我想这种“变通办法”实际上是一个合适的长期解决方案。

虽然我更喜欢我的解释,但如果需要,我可以使用此处提供的解决方案。

虽然我当然知道你的期望来自哪里,但我创建bluebird-global的主要原因是让 TypeScript 知道,从第三方代码创建和返回的 Promise 实际上是 Bluebird Promise 的实例,其中除了在全局 Promise 符号上公开所有 Bluebird 的实例和静态方法之外,没有其他_不烦人的_替代方法。 正如我之前提到的,它的完成方式不是一个简单的class Promise<T> extends Bluebird<T> {} (虽然它最初是),而是一个经过精心修补的全局 Promise 符号。 正如我所提到的,我宁愿避免维护任何东西,因为有一个已知的替代方案,它不会真正让你把头发从头上拉出来。

很抱歉对这个说“不”。 如果有更多人要求此特定功能,我将重新考虑添加它。 我不想在这里听起来很权威——这是一个开源项目,任何人都可能会推动这个功能。我想在这里表达的一点是,在我看来,这样做的好处是不超过维护它的成本。

干杯。

说得通。 感谢您的方法背后的思考。

@d-ph 以下内容对您是否有意义...我收到一条错误消息,指出“反射”不是以下代码中的函数:

image

虽然在编辑器的智能感知中,它正确地识别出映射函数中的属性p是一个 Bluebird 承诺,并且具有仅在 Bluebird 上找到的扩展 API 表面(相对于 Promise)。

image

我只是无法从中做出正面或反面。 我确实注意到,当我检查地图迭代器变量的 _type_ 时,它确实显示为:

image

我想这最终是我得到bluebird-global定义的有限 API 表面的原因,但我不知道为什么它不能正确解析。

你好。

我无法重现:/那些代码片段在我的设置中工作。

首先。 您没有在allSettled()函数中使用bluebird-global 。 您直接使用Bluebird键入。 这不是问题,但也许您没有意识到这一点。 以下代码段使用bluebird-global

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

    return reflections;
}

即该片段类型为全局Promise (在bluebird-global.d.ts中使用 Bluebird 的方法进行了修补)。 正如我所说:这是供您参考的,以防您不知道,因为您和我的片段的工作方式相同。

回到缺少 Bluebird 方法的问题。 我的猜测是:您不会在运行时将全局Promise替换为 Bluebird,然后使用全局 Promise 而不是 Bluebird 构建的 Promises 运行allSettled()

让我向您展示我的代码和一些屏幕截图。

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
_Pic 1: Array.map() 中的承诺是 Bluebird(您可以通过下划线属性的存在来判断,例如: _bitField )_

image
_Pic 2:Promise.reflect 确实在循环中定义_

你能像我一样在 Chrome 开发工具中设置一个 js 断点,看看.map promise里面的 promise 是什么吗? 更好的是:您是否可以在控制台中键入Promise并查看是否得到以下输出:
image

如果你得到以下输出,那么你没有在运行时用 Bluebird 替换全局 Promise:
image

在这种情况下,您需要这样做。 例如,在您的条目文件中像我一样。

最后,只是一点开发反馈:我个人会使用Promise<T>[]而不是Array<Promise<T>> 。 但这当然取决于开发人员的偏好。 我刚来自 C 背景,没有模板,开发人员使用数组访问运算符来定义类型。

干杯。

非常感谢您提供如此详尽的解释。 我不确定的一件事是以下几点:

导入'expose-loader?Promise!bluebird';

@d-ph ahhh,上面的一个衬里是我所缺少的。 没有你的帮助永远不会到达那里! 可能只是我,但我认为如果README文本引用了Expose Loader的使用会很有帮助。

虽然公平地说,如果这需要使用 webpack,我仍然不是 100%? 我的目标不是浏览器,只是一个节点功能。

事实上,它看起来确实没有完全工作,因为当我尝试执行文件时出现以下错误(运行时之前编辑器中没有错误):

错误:找不到模块 'expose-loader?Promise!bluebird'

你是对的, expose-loader是一个 webpack 的东西(一个 webpack 加载器)。 所以如果你不让 webpack 处理那个import语句,它就不会运行(即你会得到“找不到模块”的错误)。

如果你不能/不使用 webpack,你需要找到另一种方法让全局 Promise 在运行时成为 Bluebird。 我对节点没有太多经验,但我刚刚发现了这一点:https://github.com/petkaantonov/bluebird/issues/1026(在节点中覆盖Promise )。

我建议了解如何在最新的节点 7 中使用 async/await。你很幸运能够生活在对开发人员可用的时代。

至于在自述文件中提到使用expose-loader :我已经在d.ts文件的顶部声明,这是开发人员在运行时用 Bluebird 替换 Promise 的工作: link 。 由于有很多方法可以做到这一点,我实际上并没有提及其中任何一种。 请记住, expose-loader相当于运行window.Promise = Bluebird 。 好吧,希望谷歌能将我的回复编入索引,这样人们就不会再寻找可能的选项太久了;p

@d-ph 期待原生 async-await 但所有这些功能都在 AWS Lambda 上,所以我现在被锁定到节点 6.10.x。 在这些函数的未来传递中,我可能会切换到 async-await 并让 Typescript 将其转换为 ES2015,但现在还不想介绍这个。

无论如何,感谢@d-ph 的链接,我会尝试这种方法。 哦,如果有人对这些函数的最终版本感兴趣(在 promise-land 中非常方便):

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

提供了完整的 intelisync/类型信息,非常好。

@d-ph 希望我可以用一个相关的问题来恢复这个问题......

当我尝试使用 bluebird-global 时,我似乎在thencatch的定义上有所不同。 我看到这些是在 bluebird-global 中专门处理的,但它似乎限制了我使用标准的 Promise api 而不是获得 bluebird。 例如:

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

失败,因为catch只需要 1 个参数。

还有一个问题:

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

失败:

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

这些应该起作用还是我做错了什么? 它们在运行时工作,只是不进行类型检查。

谢谢!

你好,

关于.catch(Error, function) ,您说.then.catch (以及更多)的处理方式与其他 Bluebird 函数不同,这是正确的。 但是,特定的.catch(Error, function)覆盖包含在 bluebird-global中。 我仔细检查了,我能够编译:

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

我检查了 TS 3.0.1 和 2.9.2。 我不知道你为什么会在这里遇到问题。 也许您的 TS 项目中有一些特定的东西在bluebird-global之后覆盖了全局 Promise。 我不知道。 也许尝试通过从一个非常基本的 TS 项目开始,然后从当前项目添加更多依赖项来缩小导致问题的范围,并查看它在哪个点中断。

关于另一个问题:我不知道为什么它不起作用。 是的,它应该工作。 请为它创建一个 github 问题,我们将从那里开始。 以下是有关该问题的一些事实:

  1. 所有bluebird-global.map() $ 所做的只是重用bluebird.d.ts.map()类型定义。 换句话说,缺陷不应该来自bluebird-global类型。
  2. 您提到的行在Promise.map()上失败,但在Bluebird.map()上有效:
import Bluebird = require('bluebird');

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

Promise.resolve([3]).map((n: number) => true); // fails
  1. 在花了一些时间解密打字稿的问题后(​​本质上:为什么 TS 得出结论n的参数应该是{} ),我得出结论bluebird.d.ts也不应该工作,但它对我来说是未知的原因。 长话短说,以下是.map()在删除所有抽象层后输入的内容:
map<U>(
    mapper: (
        item: U,
        index: number,
        arrayLength: number
    ) => U | PromiseLike<U>,
    options?: Bluebird.ConcurrencyOption
): Bluebird<T extends Iterable<any> ? U[] : never>;

它说mapper函数的返回类型应该与item的类型相同(或相同的 Promise)。 在您的示例中,项目的类型是number并且返回类型是boolean 。 我无法理解为什么在直接使用Bluebird时会编译,但在使用全局 Promise 时不会。 顺便说一句,当我将示例中的返回类型更改为任意数字时,它仍然不起作用。 但是,当我说item可以是any类型时,它确实有效。 bluebird.d.tstype IterableItem<R>及其在这种情况下的用法有问题。

@d-ph


编辑:

我再次检查了map()的“未分层”表单,并且mapper函数的类型没有与item的类型具有相同的返回类型(我以为曾是)。 我的错。

所有 bluebird-global 对 .map() 所做的只是重用 bluebird.d.ts 的 .map() 类型定义。

问题是当您从通用类Bluebird<R>复制类型时,它默认为{}R因为它无法从父类推断它?

我想知道map: typeof Bluebird<T>.prototype.map会起作用吗? (我还没试过这个)

重要的:
如果使用@types/bluebird-global ,请删除您的依赖项@types/bluebird ,如@d-ph 所说

npm install --save-dev @types/bluebird-global然后按照我在打字中包含的说明进行操作:链接(链接更新于 2017-04-02)。 仅此一项就可以解决问题(即不需要手动导入/重新分配)。

作为旁注:您不再需要在package.json::devDependencies #$ 中提及@types/bluebird ,因为这是自动暗示的。

两者都导致@types/bluebird返回的类型与我的全局 Promise ( @types/bluebird-global ) 之间的匹配失败

此页面是否有帮助?
0 / 5 - 0 等级