【问题标题】:Flowtype: dynamically extending classesFlowtype:动态扩展类
【发布时间】:2016-05-11 11:03:59
【问题描述】:

是否可以为现有类手动定义其他方法?

我的具体用例是 bluebird 的 promisifyAll(),其中:

通过遍历对象的属性并创建对象及其原型链上每个函数的异步等效项来承诺整个对象...http://bluebirdjs.com/docs/api/promise.promisifyall.html

显然,flow 无法自动解决这个问题。所以,我愿意帮助它。问题是如何?

考虑下面的代码

import http from 'http'
import { promisifyAll } from 'bluebird'

promisifyAll(http)

const server = http.createServer(() => { console.log('request is in'); })
server.listenAsync(8080).then(() => {
  console.log('Server is ready to handle connections')
})

Flow 在这里给出以下错误:

property `listenAsync`. Property not found in
Server

如果我使用listen,不会有任何错误。 flow 足够聪明,可以看出这是在模块中定义的真实方法。但是listenAsyncpromisifyAll 的动态添加,对流是不可见的

【问题讨论】:

    标签: javascript flowtype


    【解决方案1】:

    这是不可能的,而且这样做并不安全。以下是您可以针对您的情况做的事情:

    首先声明bluebird如下:

    declare module "bluebird" {
      declare function promisifyAll(arg: any): any
    }
    

    然后这样做:

    import httpNode from 'http'
    import { promisifyAll } from 'bluebird'
    import type { Server } from 'http'
    
    
    type PromisifiedServer = Server & {
      listenAsync(port: number, hostname?: string, backlog?: number): Promise<PromisifiedServer>;
    };
    
    type PromisifiedHttp = {
      createServer(listener: Function): PromisifiedServer;
    };
    
    const http: PromisifiedHttp = promisifyAll(httpNode)
    

    这里我们手动将http 转换为PromisifiedHttp。我们仍然需要手动声明所有承诺的类型,尽管我们可以使用类型交集来扩展现有类型。

    【讨论】:

    • 谢谢。这并不完美,因为它需要更改代码。微小的变化,但仍然。这意味着代码也必须针对其他动态情况进行更改。我理解“不会真正安全”的部分,但这并不现实,因为在这两种情况下编译器都无法从代码中推断出数据并相信我会编写正确的定义。
    • 一般来说,无法在流中表达一些动态模式。您必须将过于动态的部分与流隔离,并为类型化部分提供适当的声明
    • 如果 flow 有一种机制可以以“不安全”的方式进行原型扩展之类的事情,它将显着减少曲线。例如,如果我使用类似 should.js 或 chai 的库,我应该能够在库中创建一个接口,该接口使用“应该”函数扩展 Object 的原型。如果这不能以类型安全的方式完成,请允许使用者禁用对那些使用它的代码路径的静态分析,而不是抛出错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-15
    • 1970-01-01
    相关资源
    最近更新 更多