【问题标题】:Extending TypeScript declaration files扩展 TypeScript 声明文件
【发布时间】:2016-09-27 02:46:41
【问题描述】:

我正在尝试使用 TypeScript 和 Express。我已经从 Typings 加载了类型声明,它们看起来像这样:

// Generated by typings
// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/express/express.d.ts
declare module "express" {
    import * as serveStatic from "serve-static";
    import * as core from "express-serve-static-core";

    /**
     * Creates an Express application. The express() function is a top-level function exported by the express module.
     */
    function e(): core.Express;

    namespace e {

        /**
         * This is the only built-in middleware function in Express. It serves static files and is based on serve-static.
         */
        var static: typeof serveStatic;

        export function Router(options?: any): core.Router;

        interface Application extends core.Application { }
        interface CookieOptions extends core.CookieOptions { }
        interface Errback extends core.Errback { }
        interface ErrorRequestHandler extends core.ErrorRequestHandler { }
        interface Express extends core.Express { }
        interface Handler extends core.Handler { }
        interface IRoute extends core.IRoute { }
        interface IRouter<T> extends core.IRouter<T> { }
        interface IRouterMatcher<T> extends core.IRouterMatcher<T> { }
        interface MediaType extends core.MediaType { }
        interface NextFunction extends core.NextFunction { }
        interface Request extends core.Request { }
        interface RequestHandler extends core.RequestHandler { }
        interface RequestParamHandler extends core.RequestParamHandler { }
        export interface Response extends core.Response { }
        interface Router extends core.Router { }
        interface Send extends core.Send { }
    }

    export = e;
}

现在我正在尝试为所有响应对象扩展原型,如下所示:

const express = require('express');
express.response.sendWrapped = function(obj: Object, meta?: Object) {
    return this.json({
        data: obj
    });
};

现在我只需要将扩展​​名添加到类型中。我很想将此方法扩展到现有定义中,就像我在原型中扩展它的方式一样,但我不确定如何去做。

由于这是库类型定义的个人扩展,我确实相信这属于主类型集,我应该必须修改出于我自己的目的手动使用它们。以我自己的方式扩展它们的最佳方法是什么?我可以在不覆盖依赖于 Response 的所有其他部分的情况下做到这一点吗?

【问题讨论】:

    标签: express typescript typescript-typings


    【解决方案1】:

    一些事情:

    (1) 在你包含的声明中没有response,有一个Response,所以应该是:express.Response.sendWrapped

    (2) 您没有为所有Responses 扩展原型,而是将sendWrapped 函数添加到类本身(我假设Response 是一个类)。
    如果你想添加到原型中,它应该是这样的:

    express.Response.prototype.sendWrapped = function(obj: Object, meta?: Object) {
        return this.json({
            data: obj
        });
    };
    

    (3) 您可以像这样添加到现有类型:

    namespace express {
        interface Response {
            sendWrapped(obj: Object, meta?: Object): any;
        }
    }
    

    更多信息请关注Declaration Merging


    编辑

    如果它在 d.ts 文件中,那么您需要它:

    declare namespace express {
        ...
    }
    

    我不确定为什么它不允许您合并声明,并且我没有此设置来自行测试它,但我有另一个解决方案供您使用,在我看来,它更好。

    只需扩展 express.Response 在其中添加您需要的任何内容,例如:

    class MyResponse extends express.Response {
        constructor() {
            super();
        }
    
        sendWrapped(obj: Object, meta?: Object): express.Response {
            return this.json({
                data: obj
            });
        }
    }
    

    这更好,因为您不会因为 express api 的变化而受到影响,而且更重要的是,这就是面向对象的用途。

    【讨论】:

    • 这里有一点不匹配,因为 Express 在后台是如何工作的。实际原型在response 下,而定义在Response 下。但这是一个实现细节。我需要的是更新界面以相应地工作。我会试试你的建议。谢谢!
    • 不幸的是,这些似乎都不适合我。我对 #3 最有希望,但是当它是自己的 .d.ts 文件时,我收到此错误:A 'declare' modifier is required for a top level declaration in a .d.ts file.。如果我尝试在普通的 .ts 文件中添加命名空间,我会收到此错误:Import declaration conflicts with local declaration of 'express'
    • declare namespace 建议消除了编译错误,但它似乎对调用它的Response 没有任何影响。不幸的是,在这里扩展类并不是一个非常干净的方法。响应对象通过类型推断传递给其他函数,我必须重写它们中的每一个来添加新方法。例如:router.get('/users/', (req, res) =&gt; /* res is of type Response via declarations */ );
    • 我相信有一个突出的 TypeScript 问题可以更好地支持这一点。 github.com/Microsoft/TypeScript/issues/819
    • 看起来和我说的完全一样,你再次声明它并添加所需的成员/方法(只有我使用了interface,他们使用了class)。如果没有编译错误但在运行时没有方法,那么你实际添加方法的方式是错误的,可能与你提到的原型问题有关。
    【解决方案2】:

    使用 TypeScript 2.0 或其预发布版本 (typescript@next),您可以使用模块扩充语法来扩充 express 的定义,以包含您的新 response 定义:

    import express = require('express');
    
    declare module "express" {
        namespace response {
            function sendWrapped(obj: any, meta?: any): void;
        }
    }
    
    express.response.sendWrapped = function(obj: Object, meta?: Object) {
        return this.json({
            data: obj
        });
    };

    【讨论】:

    • 这必须在 TS 文件中声明还是可以在 d.ts 中声明?
    • 您可以在 .ts 和 .d.ts 中执行此操作
    • 你是如何让你的 typescript 2.0 识别 express 框架的?
    猜你喜欢
    • 2018-03-11
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 2021-05-03
    • 1970-01-01
    • 2018-05-25
    • 2021-12-14
    • 2020-05-15
    相关资源
    最近更新 更多