4

Considering an external (npm) module extmod exposing the following interface in its declarations file:

interface Options {
  somevar?: string;
  suboptions?: {
    somesubvar?: string;
  };
}

How can I add a property somesubvar2 inside suboptions with module augmentation?

I've tried the following in an extmod.d.ts file:

declare module 'extmod' {
  interface Options {
    suboptions?: {
      somesubvar2?: string;
    };
  }
}

But it throws the following errors:

error TS2687: All declarations of 'suboptions' must have identical modifiers.
error TS2717: Subsequent property declarations must have the same type.  Property 'suboptions' must be of type '<SNIP>', but here has type '{ somesubvar2: string; }'.
Zoddo
  • 163
  • 6
  • You might want to have a look at [indexable types](https://www.typescriptlang.org/docs/handbook/interfaces.html#indexable-types) or simply use mutiple interfaces. I don't think you can "nest" them. – RienNeVaPlu͢s May 10 '20 at 17:45
  • You can't merge fields like this... see [Module declaration with same name for property and function](https://stackoverflow.com/questions/51703264/module-declaration-with-same-name-for-property-and-function); does that answer your question? – jcalz May 10 '20 at 17:47
  • Maybe I was wrong, [have a look](https://know-thy-code.com/how-to-nest-typescript-interfaces/) – RienNeVaPlu͢s May 10 '20 at 17:49
  • 1
    Or [How can I augment a property within a third-party TypeScript interface defined as “any”?](https://stackoverflow.com/questions/48690619/how-can-i-augment-a-property-within-a-third-party-typescript-interface-defined-a?noredirect=1&lq=1) – jcalz May 10 '20 at 17:49
  • @RienNeVaPlu͢s Thanks, but I'm not the one who write the declarations file in the library. But yes, having a nested interface would have allowed me to easily add my property. – Zoddo May 10 '20 at 18:03
  • @jcalz Thanks for the idea of defining a new property. Unfortunately, that won't work in my case because the said interface is used in multiple functions' arguments defined by the library itself... – Zoddo May 10 '20 at 18:07
  • 1
    Are you using a third-party library with a declaration file? If so you might need to copy it locally, modify it however you want, and use the modified version. As for "the said interface is used in multiple functions' arguments defined by the library itself"... but it wouldn't have a problem with `somesubvar2` being a required property of `suboptions`? – jcalz May 10 '20 at 19:37
  • @jcalz yes, it's a third-party library which contains a single declaration file (the lib itself is written in pure JS). `somesubvar2` is an optional property in reality (I'll fix the example), but good catch :) – Zoddo May 10 '20 at 20:06

2 Answers2

0

This could have been done probably better, made available globally using ambient declarations, but it still makes the job done.

import Web3 from 'web3'
import type { Contract as TheBadContract } from 'xyz'

interface ContractMethods {
  // some properties...
}

interface Contract extends Modify<TheBadContract, {
  methods: ContractMethods // <- this `methods` is the actual overwritten property
}> {}

const contract: Contract = new web3.eth.Contract()

This was easy as the methods object was an immediate member and it is undefined on the original Contract type.

If you need to actually modify some deeply nested key, check out my ModifyDeep type below.

Modify: https://stackoverflow.com/a/55032655/985454
ModifyDeep: https://stackoverflow.com/a/65561287/985454

Qwerty
  • 29,062
  • 22
  • 108
  • 136
-1

How can I add a property somesubvar2 inside suboptions with module augmentation?

In your example you changed the type suboptions from <SNIP> to { somesubvar2: string; }

You could patch <SNIP> type with additional property.

Józef Podlecki
  • 10,453
  • 5
  • 24
  • 50