Typescript接口合并使返回类型更具体

时间:2017-12-27 08:22:10

标签: typescript express interface

我想使用自定义类型定义来使Express API中的返回类型更具体。我们正在使用app.setapp.get来保留应用程序中的全局对象。

app.get('foo')会返回特定的类MyClass,因此我想使用TypeScript表达这一事实,以避免必须明确转换。

包含的app.getindex.d.ts的现有定义如下:

get: ((name: string) => any) & IRouterMatcher<this>;

在我的自定义类型定义中,我添加了以下内容:

import { MyClass } from '../MyClass';

declare global {
  namespace Express {
    export interface Application {
      get (name: 'foo'): MyClass;
      // also tried this to conform to existing structure:
      // get: ((name: 'foo') => MyClass);
    }
  }
}

但在这两种情况下,app.get('foo')的返回类型仍为any

在执行以下操作时,是否可以隐式具有正确的类型......:

let myObject = app.get('foo');

...并且避免写作:

let myObject: MyClass = app.get('foo');

1 个答案:

答案 0 :(得分:1)

好吧,对于express.js type definitions的当前版本,我发现您可以使用此代码扩充get函数。

custom.d.ts

import { MyClass } from './MyClass';

declare module 'express-serve-static-core' {
  export interface IRouterMatcher<T> {
    (name: 'foo'): MyClass;
  }
}

说明:

不幸的是,这是一个有点黑客的解决方案,因为你使用declaration merging看似无关的界面。 您需要执行此操作,因为您无法像this中那样使用全局Express命名空间扩充:

declare namespace Express {  
  export interface Application {
    get(name: 'foo'): MyClass; //doesn't work :(
  }
}

因为如果您仔细查看输入内容,您会发现set中的getExpress.Application方法被覆盖并使用extends关键字。

export interface Application extends IRouter, Express.Application {
  ...
  set(setting: string, val: any): Application;
  get: ((name: string) => any) & IRouterMatcher<this>;
  ...
}

您也无法扩充getset方法,因为如果更改属性类型,声明合并不起作用。

declare module 'express-serve-static-core' {
  export interface Application {
    get: ((name: string) => any) &
      IRouterMatcher<this> &
      ((name: 'foo') => MyClass);
      //Error: 'Error: Subsequent variable declarations must have the same type. :(
  }
}

我认为更清洁的解决方案是改变DefinitelyTyped typing。它可以类似于在previously提到的问题中对Request对象进行扩充的方式(get签名需要表示为可以与自定义类型合并的接口)