0

I know that interfaces in typescript allow us to merge different types. When i tried to do so, i am getting error while transpiling the script.

Here is my buggy interface

export interface StoreConfig extends Document, TimeStamps {
  type: 'webhook'
  metadata: {
    endpoint: string
    method: HttpMethod
    secret: string
    event: string | string[]
  }
}

export interface StoreConfig extends Document, TimeStamps {
  type: 'buylink'
  metadata: {
    prodId: string
    key: string
    expire: Date
  }
}

export interface StoreConfig extends Document, TimeStamps {
  type: 'paymentmethod'
  metadata: {
    apiKey: string
    mode: string
    whsecret: string
  }
}

I am getting this error on transpiling ts script

Subsequent property declarations must have the same type.  Property 'type' must be of type '"webhook"', but here has type '"buylink"'.

PS: I have seen many libraries (for example: nodemailer, inquirer) are loading typings based on some flag or condition.

tbhaxor
  • 1,659
  • 2
  • 13
  • 43
  • Name the interfaces differently and then `export type StoreConfig = Interface1 | Interface2 | Interface3;` – Roberto Zvjerković Dec 16 '20 at 09:11
  • 2
    This is expected behavior. _Non-function members of the interfaces should be unique. If they are not unique, they must be of the same type. The compiler will issue an error if the interfaces both declare a non-function member of the same name, but of different types._ https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces – Aleksey L. Dec 16 '20 at 09:16

1 Answers1

1
/**
 * Simplified example
 */

export interface StoreConfig extends Document {
    type: 'webhook'

}

export interface StoreConfig extends Document {
    type: 'buylink'

}

export interface StoreConfig extends Document {
    type: 'paymentmethod'
}

/**
 * This is how it works
 * 1) 
 */

export interface A {
    type: 'buylink'

}

export interface A {
    payload: number
}

type O = keyof A // type | payload

/**
 * Because you can't do smth like that
 */

type CustomType = 'buylink' & 'webhook' // never

/**
 * Above type is never because it is irrepresentable
 * Please treat merging as & operator on high level
 */

Demo1

What you need to do is to make a union type. Just like @ritaj wrote in his comment:

export interface StoreConfig1 extends Document {
    type: 'webhook'

}

export interface StoreConfig2 extends Document {
    type: 'buylink'

}

export interface StoreConfig3 extends Document {
    type: 'paymentmethod'
}

type StoreConfig = StoreConfig1 | StoreConfig2 | StoreConfig3

Demo2

  • When i am doing this I am getting `Type 'StoreConfig' does not satisfy the constraint 'Document'.` on mongoose model function. This is my code in another file `model(Model.StoreConfiguration, schema)` – tbhaxor Dec 16 '20 at 09:20
  • @tbhaxor sorry, I'm not aware about mongoose context here – captain-yossarian from Ukraine Dec 16 '20 at 09:21
  • also when I am adding new field `metadata` with each interface (which is again an interface), I am only seeing the common fields (only those which have same type and name in all three main StoreConfig interfaces) See this loom video for example, https://www.loom.com/share/2df3da5a9afc4462838bf14d66daceb9 – tbhaxor Dec 16 '20 at 09:32
  • Share your STORE_CONFIG class. You need to do small refactor, because STORE CONFIG instance should already have all properties defined – captain-yossarian from Ukraine Dec 16 '20 at 10:00
  • I have created a gist [here](https://gist.github.com/tbhaxor/f36aa9b02e63eb552b5a99eb05357e9c) – tbhaxor Dec 16 '20 at 10:35
  • I have a question, I usually have to provide the type with `as` keyword when I am using union types. So here also when I see the typings are being guessed by vscode. Since @Aleksey said type overloading is only supported by the functions or methods. So i think the issue is resolved. If I am wrong anywhere please correct me – tbhaxor Dec 16 '20 at 10:52
  • Small tip: there are only few cases when you need to use `as` operator. So my rule of thumb (90%): if you use `as`, you probably did smth wrong – captain-yossarian from Ukraine Dec 16 '20 at 10:58
  • @tbhaxor please share gist with whole your code, I will try to help – captain-yossarian from Ukraine Dec 16 '20 at 11:41
  • I have included instructions, loom video and buggy code in this [gist](https://gist.github.com/tbhaxor/f09937ba8224049cb06780567ded04d1). Since this code is from a product, i can't share the whole code base. So I just picked the buggy code. – tbhaxor Dec 16 '20 at 12:04
  • @tbhaxor You need just create builder function. Please see the demo https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBASwHY2FAZgQwMbDgZRmmAGEIl0EBzARjlFSQBMBnOAEQmwFcBbYFHADeAKDji4MAJ5hgALjgByAO7AARgAsIEANaKRIgL4HQkWIhRosuAkSilylKgCZ6IRqw5c+A+KImSMvJKatxSADbIegbGIqbQ8MioGDh4hMRkFNQAzG4ebJw8-IL+EtKyCopgmFLFMPwwWkz6seVpdg5ZVHAAvLYZjtR0AD799plOrqPp44NU2QbY5CzwoQjhTGi9cAAUS11yM51OAJQ9AHyl4vsrcCsDXdtIwMoEACoA8gBKAKIA+iQPgA5ABiAEkAOI7E4AbjEEnsMG4UCQwnhAXEADpsfdZl0ADTojHYzH7JxE4zGIA – captain-yossarian from Ukraine Dec 16 '20 at 13:02
  • that what i was wondering to overload builder function in order to fix this issue – tbhaxor Dec 16 '20 at 13:20