Ben
Ben

Reputation: 3654

How to override external TypeScript interface

I am using passport in a TypeScript project. The DefinitelyTyped type definition for passport overrides the Express request to include the user property. But it defines the user as being an empty interface:

index.d.ts

declare global {
    namespace Express {
        ...
        // tslint:disable-next-line:no-empty-interface
        interface User {}

        interface Request {
            ...
            user?: User;
            ...
        }
    }
}

However throughout my application I want req.user to be this type interface:

interface User {
    id: number
    username: string,
    profilePicture: string,
    name: string
}

I am tired of writing req.user as User | null throughout my application. I could override the interface definition in the definition file directly but this seems bad practise modifying a file in node_modules that will likely get overwritten if I update the type module.

Is there a way to write a definition file in my src folder that overrides Express.User? I have tried myself copying and amending the definition file to my src directory but it says

Augmentations for the global scope can only be directly nested in external modules or ambient module declarations

Without declare global tsc still treats req.user as being of an empty interface.

What configuration do I have to include in tsconfig.json to then pickup this override?

Upvotes: 6

Views: 5657

Answers (1)

Aluan Haddad
Aluan Haddad

Reputation: 31823

Interface declarations in the same scope are merged. That is to say, the following

interface A {
  name: string;
}

interface A {
  id: number;
}

declares a single interface, namely A, with two properties, name and id.

Therefore, simply use the same technique used by passport to adjust the types.

My convention is to create an augmentations file in the root of my project when I want to augment the type declarations of any dependencies such as express.

augmentations.d.ts

// ensure file is parsed as a module
export {}

// access the global scope inside our module
declare global {
  namespace Express {
    // introduce another declaration of interface Express.User which will merge with any others
    interface User {
      id: number,
      username: string,
      profilePicture: string,
      name: string
    }
  }
}

Upvotes: 11

Related Questions