扩展 TypeScript 声明文件

Posted

技术标签:

【中文标题】扩展 TypeScript 声明文件【英文标题】:Extending TypeScript declaration files 【发布时间】: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 的所有其他部分的情况下做到这一点吗?

【问题讨论】:

【参考方案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 框架的?

以上是关于扩展 TypeScript 声明文件的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript入门学习之路

在扩展 EventEmitter 的 TypeScript 类中声明事件

如何扩展 TypeScript 的类型声明?

无法在 TypeScript 中扩展 Express 请求

尝试执行“npx typescript --init”“npm ERR!无法确定要运行的可执行文件”

LayaBox---TypeScript---声明合并