David Pfeffer
David Pfeffer

Reputation: 39823

Declaration merging with ES6 style modules

I'd like to add a property, id, to Express's Request interface. Express has a DefinitelyTyped type definition. I have tried all manner of specifying the interface for merging, all of which result in an error or do not work.

I'm accessing Express's typings using ES6 style module imports: import * as express from 'express';

I've tried merging with the Request object in the Express namespace.

declare module Express {
    export interface Request {
        id: number;        
    }
}

This silently does nothing. I've tried merging with the actual module instead of the namespace, following the instructions of the new 1.8 compiler which I am using:

import { Request } from 'express';

declare module 'express' {
    interface Request {
        id: number;        
    }    
}

This errors because Module augmentation cannot introduce new names in the top level scope.

When I open up the actual express.d.ts file, it looks like there's a module e { ... } containing all of the interfaces, inside of a declare module "express" { ... } which contains a line export = e;. Maybe this is somehow the problem, because of the namespace nesting?

How do you properly do this?

Upvotes: 8

Views: 2268

Answers (4)

Calin Vlasin
Calin Vlasin

Reputation: 1433

My problem was that in package.json I had "typescript": "2.0.3" and on the system I have the 2.3.3 version installed.

I removed the 2.3.3 version and installed the 2.0.3 version, and it worked.

Upvotes: 0

Manu Artero
Manu Artero

Reputation: 10243

I want to add my 2 cents here; this is how I would add id property to Request

  1. Define wherever you want a .d.ts file; it's going to contain your custom types shared across the whole project I usually call it index.d.ts You won't be able to import types from modules in this file (since it's an ambient declaration file). In this example:

index.d.ts

interface Identificable {
  id: number
}
  1. In your typescript file, import Request as usual and define a new type which applies both Request and your type.

handler.ts

import { Request, Response } from 'express'

type IdentificableRequest = Request & Identificable

function myHandler(req: IdentificableRequest, res: Response) {
  const id = req.id // fine
  const params = req.params // fine too
  ... 
}

Upvotes: 0

David Pfeffer
David Pfeffer

Reputation: 39823

Apparently, a compiler issue causes this problem:

https://github.com/Microsoft/TypeScript/issues/6722

Hopefully this will be resolved soon.

Upvotes: 0

Fenton
Fenton

Reputation: 250822

In TypeScript versions prior to v1.8 this was not allowed.

From v1.8 onwards, module augmentation is available. The syntax is identical to ambient declarations (as you have shown in your question) - the only difference is that what you have posted above should work now.

Module augmentation allows you to extend global and module scope.

To extend the global scope, you would use global as three module name:

declare global {
    interface Array<T> {
        popFromTop(): T;
    }
}

Upvotes: 1

Related Questions