6

I have a file named service.ts which exposes the following code:

export interface SomeInterface {
  keyOne: string;
}

export class TestService<T = SomeInterface> {
  property: T;
}

In index.ts file I am using the service:

import { TestService } from './service';

const service = new TestService();
service.property.keyOne

I also created index.d.ts file which declare the same interface SomeInterface with more keys:

export interface SomeInterface {
  keyTwo: number;
}

The problem is that service.property only "knows" the keyOne property. How can I tell typescript to merge both of them?

https://stackblitz.com/edit/typescript-cp8zmv

2 Answers 2

13

If I understand you correctly (your comment in @chris p bacon's answer), you want to augment a module type definition from a library. The link to declaration merging in TypeScript docs is already a good catch. There are some good answers out there dealing with third party lib type extensions: here and here.

For your example, if we want to augment a library module type definition for some reason (let's say vendor-lib.d.ts instead of your index.d.ts to make it clearer), we can do that via Module Augmentation:

vendor-lib.d.ts:

export interface SomeInterface {
  keyTwo: number
}

service.ts

// here for simplicity a relative import
import { SomeInterface } from "./vendor-lib"

// Augment above imported module. 
// Important: this file must be a module (not a script) via `import/export`.
// Then augmentation will work. Otherwise compiler expects a module declaration.
declare module "./vendor-lib" {
  interface SomeInterface {
    keyOne: string
  }
}

index.ts:

const service = new TestService(); service.property = {...};
service.property.keyOne // works
service.property.keyTwo // works

StackBlitz

Sign up to request clarification or add additional context in comments.

Comments

3

You'd extend the interface and give it another name

export interface SomeInterface {
  keyOne: string;
}

export interface SomeExtendingInterface extends SomeInterface {
  keyTwo: number;
}

Or merge them to a type that has both properties

interface Foo {
    foo: string;
}

interface Bar {
    bar: string;
}

type Baz = Foo & Bar;

const foo: Baz = {
    foo: '',
    bar: ''
};

4 Comments

It should work as I did according to the docs typescriptlang.org/docs/handbook/declaration-merging.html
No matter if it works or not, why should two different interfaces ever have the same name? Don’t you think that’s confusing in a few months when maintaining your code? But do what you prefer...
The purpose is for users that use a library to be able to extend the interface globally.
@undefined Honestly, you should add that in your question as context, otherwise, it doesn't really make that much sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.